Track space sort keys
This commit is contained in:
@@ -108,8 +108,13 @@ impl BrowserCore {
|
|||||||
pub fn new(config: InitialBrowserConfig) -> Result<Self, CoreError> {
|
pub fn new(config: InitialBrowserConfig) -> Result<Self, CoreError> {
|
||||||
let profile = Profile::new(config.profile_name, 0x26251e, ProfileKind::Standard);
|
let profile = Profile::new(config.profile_name, 0x26251e, ProfileKind::Standard);
|
||||||
let active_profile_id = profile.id().clone();
|
let active_profile_id = profile.id().clone();
|
||||||
let space =
|
let space = Space::new(
|
||||||
Space::new(config.space_name, config.space_icon, 0xf54e00, active_profile_id.clone());
|
config.space_name,
|
||||||
|
config.space_icon,
|
||||||
|
0xf54e00,
|
||||||
|
active_profile_id.clone(),
|
||||||
|
0,
|
||||||
|
);
|
||||||
let new_tab_destination = config.new_tab_destination;
|
let new_tab_destination = config.new_tab_destination;
|
||||||
let new_tab_url = new_tab_destination.url()?;
|
let new_tab_url = new_tab_destination.url()?;
|
||||||
let new_tab_title = tab_title(&new_tab_url);
|
let new_tab_title = tab_title(&new_tab_url);
|
||||||
@@ -163,7 +168,8 @@ impl BrowserCore {
|
|||||||
icon: impl Into<String>,
|
icon: impl Into<String>,
|
||||||
accent_hex: u32,
|
accent_hex: u32,
|
||||||
) -> Result<SpaceId, CoreError> {
|
) -> Result<SpaceId, CoreError> {
|
||||||
let space = Space::new(name, icon, accent_hex, self.active_profile_id.clone());
|
let sort_key = self.next_space_sort_key();
|
||||||
|
let space = Space::new(name, icon, accent_hex, self.active_profile_id.clone(), sort_key);
|
||||||
let space_id = space.id().clone();
|
let space_id = space.id().clone();
|
||||||
let default_profile_id = space.default_profile_id().clone();
|
let default_profile_id = space.default_profile_id().clone();
|
||||||
let tab = self.build_tab_for(space_id.clone(), default_profile_id, self.new_tab_url()?);
|
let tab = self.build_tab_for(space_id.clone(), default_profile_id, self.new_tab_url()?);
|
||||||
@@ -266,6 +272,20 @@ impl BrowserCore {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_space_sort_key(
|
||||||
|
&mut self,
|
||||||
|
space_id: &SpaceId,
|
||||||
|
sort_key: u64,
|
||||||
|
) -> Result<(), CoreError> {
|
||||||
|
let space = self
|
||||||
|
.spaces
|
||||||
|
.iter_mut()
|
||||||
|
.find(|space| space.id() == space_id)
|
||||||
|
.ok_or_else(|| CoreError::SpaceNotFound { id: space_id.clone() })?;
|
||||||
|
space.set_sort_key(sort_key);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_search_engine(&mut self, search_engine: SearchEngine) {
|
pub fn set_search_engine(&mut self, search_engine: SearchEngine) {
|
||||||
self.search_engine = search_engine;
|
self.search_engine = search_engine;
|
||||||
}
|
}
|
||||||
@@ -329,7 +349,7 @@ impl BrowserCore {
|
|||||||
split_layouts: self.visible_split_layouts(),
|
split_layouts: self.visible_split_layouts(),
|
||||||
installed_plugins: self.installed_plugins.clone(),
|
installed_plugins: self.installed_plugins.clone(),
|
||||||
plugin_audit_events: self.plugin_audit_events.clone(),
|
plugin_audit_events: self.plugin_audit_events.clone(),
|
||||||
spaces: self.spaces.clone(),
|
spaces: self.sorted_spaces(),
|
||||||
profiles: self.profiles.clone(),
|
profiles: self.profiles.clone(),
|
||||||
sync_status: self.sync_status(),
|
sync_status: self.sync_status(),
|
||||||
tabs: self.visible_tabs(),
|
tabs: self.visible_tabs(),
|
||||||
@@ -365,6 +385,22 @@ impl BrowserCore {
|
|||||||
.ok_or_else(|| CoreError::SpaceNotFound { id: self.active_space_id.clone() })
|
.ok_or_else(|| CoreError::SpaceNotFound { id: self.active_space_id.clone() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_space_sort_key(&self) -> u64 {
|
||||||
|
self.spaces
|
||||||
|
.iter()
|
||||||
|
.map(Space::sort_key)
|
||||||
|
.max()
|
||||||
|
.map_or(0, |sort_key| sort_key.saturating_add(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sorted_spaces(&self) -> Vec<Space> {
|
||||||
|
let mut spaces = self.spaces.clone();
|
||||||
|
spaces.sort_by(|left, right| {
|
||||||
|
left.sort_key().cmp(&right.sort_key()).then_with(|| left.id().cmp(right.id()))
|
||||||
|
});
|
||||||
|
spaces
|
||||||
|
}
|
||||||
|
|
||||||
fn favorites(&self) -> Vec<BrowserTab> {
|
fn favorites(&self) -> Vec<BrowserTab> {
|
||||||
self.tabs.iter().filter(|tab| tab.flags().favorite).cloned().collect()
|
self.tabs.iter().filter(|tab| tab.flags().favorite).cloned().collect()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,42 @@ fn created_space_uses_default_sidebar_width() -> Result<(), Box<dyn Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn created_spaces_receive_incrementing_sort_keys() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||||
|
let work_space_id = core.snapshot()?.active_space_id;
|
||||||
|
let research_space_id = core.create_space("Research", "R", 0x9fc9a2)?;
|
||||||
|
|
||||||
|
let snapshot = core.snapshot()?;
|
||||||
|
let Some(work_space) = snapshot.spaces.iter().find(|space| space.id() == &work_space_id) else {
|
||||||
|
return Err("missing work space".into());
|
||||||
|
};
|
||||||
|
let Some(research_space) =
|
||||||
|
snapshot.spaces.iter().find(|space| space.id() == &research_space_id)
|
||||||
|
else {
|
||||||
|
return Err("missing research space".into());
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(work_space.sort_key(), 0);
|
||||||
|
assert_eq!(research_space.sort_key(), 1);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn snapshot_orders_spaces_by_sort_key() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||||
|
let work_space_id = core.snapshot()?.active_space_id;
|
||||||
|
let research_space_id = core.create_space("Research", "R", 0x9fc9a2)?;
|
||||||
|
|
||||||
|
core.set_space_sort_key(&work_space_id, 20)?;
|
||||||
|
core.set_space_sort_key(&research_space_id, 10)?;
|
||||||
|
let snapshot = core.snapshot()?;
|
||||||
|
|
||||||
|
assert_eq!(snapshot.spaces[0].id(), &research_space_id);
|
||||||
|
assert_eq!(snapshot.spaces[1].id(), &work_space_id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn space_default_profile_updates_with_profile_validation() -> Result<(), Box<dyn Error>> {
|
fn space_default_profile_updates_with_profile_validation() -> Result<(), Box<dyn Error>> {
|
||||||
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||||
@@ -91,9 +127,13 @@ fn space_settings_refresh_updated_at() -> Result<(), Box<dyn Error>> {
|
|||||||
core.set_space_sidebar_width(&work_space_id, 320)?;
|
core.set_space_sidebar_width(&work_space_id, 320)?;
|
||||||
let after_sidebar_update = active_space_updated_at(&core, &work_space_id)?;
|
let after_sidebar_update = active_space_updated_at(&core, &work_space_id)?;
|
||||||
|
|
||||||
|
core.set_space_sort_key(&work_space_id, 8)?;
|
||||||
|
let after_sort_update = active_space_updated_at(&core, &work_space_id)?;
|
||||||
|
|
||||||
assert!(after_archive_update > before_update);
|
assert!(after_archive_update > before_update);
|
||||||
assert!(after_profile_update > after_archive_update);
|
assert!(after_profile_update > after_archive_update);
|
||||||
assert!(after_sidebar_update > after_profile_update);
|
assert!(after_sidebar_update > after_profile_update);
|
||||||
|
assert!(after_sort_update > after_sidebar_update);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ pub struct Space {
|
|||||||
default_profile_id: ProfileId,
|
default_profile_id: ProfileId,
|
||||||
archive_policy: ArchivePolicy,
|
archive_policy: ArchivePolicy,
|
||||||
sidebar_width_px: u16,
|
sidebar_width_px: u16,
|
||||||
|
sort_key: u64,
|
||||||
created_at: SystemTime,
|
created_at: SystemTime,
|
||||||
updated_at: SystemTime,
|
updated_at: SystemTime,
|
||||||
}
|
}
|
||||||
@@ -30,6 +31,7 @@ impl Space {
|
|||||||
icon: impl Into<String>,
|
icon: impl Into<String>,
|
||||||
accent_hex: u32,
|
accent_hex: u32,
|
||||||
default_profile_id: ProfileId,
|
default_profile_id: ProfileId,
|
||||||
|
sort_key: u64,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let created_at = SystemTime::now();
|
let created_at = SystemTime::now();
|
||||||
Self {
|
Self {
|
||||||
@@ -40,6 +42,7 @@ impl Space {
|
|||||||
default_profile_id,
|
default_profile_id,
|
||||||
archive_policy: ArchivePolicy::Manual,
|
archive_policy: ArchivePolicy::Manual,
|
||||||
sidebar_width_px: DEFAULT_SIDEBAR_WIDTH_PX,
|
sidebar_width_px: DEFAULT_SIDEBAR_WIDTH_PX,
|
||||||
|
sort_key,
|
||||||
created_at,
|
created_at,
|
||||||
updated_at: created_at,
|
updated_at: created_at,
|
||||||
}
|
}
|
||||||
@@ -95,6 +98,16 @@ impl Space {
|
|||||||
self.record_update();
|
self.record_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn sort_key(&self) -> u64 {
|
||||||
|
self.sort_key
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_sort_key(&mut self, sort_key: u64) {
|
||||||
|
self.sort_key = sort_key;
|
||||||
|
self.record_update();
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn created_at(&self) -> SystemTime {
|
pub fn created_at(&self) -> SystemTime {
|
||||||
self.created_at
|
self.created_at
|
||||||
|
|||||||
Reference in New Issue
Block a user