Add reading list progress percent

This commit is contained in:
2026-05-08 06:43:38 -04:00
parent 8dd610fec3
commit bae3c7789f
8 changed files with 169 additions and 15 deletions
+25 -1
View File
@@ -1,4 +1,6 @@
use ely_domain::{BrowserTab, PluginId, SearchEngine, SiteOrigin, UrlText};
use ely_domain::{
BrowserTab, DomainError, PluginId, ReadingProgressPercent, SearchEngine, SiteOrigin, UrlText,
};
use url::Url;
use crate::CoreError;
@@ -67,6 +69,28 @@ pub(crate) fn archive_idle_days(command: &str) -> Option<u16> {
.and_then(|value| value.parse().ok())
}
pub(crate) fn reading_progress_percent(
command: &str,
) -> Result<Option<ReadingProgressPercent>, CoreError> {
let Some(value) = command_argument(
command,
&[
"reading-progress ",
"reading progress ",
"set-reading-progress ",
"set reading progress ",
],
) else {
return Ok(None);
};
let percent_text = value.trim().strip_suffix('%').unwrap_or(value.trim()).trim();
let percent = percent_text.parse::<u8>().map_err(|_| {
DomainError::InvalidReadingProgressPercent { value: value.trim().to_string() }
})?;
ReadingProgressPercent::new(percent).map(Some).map_err(CoreError::from)
}
pub(crate) fn new_profile_name(command: &str) -> Option<&str> {
command_argument(command, &["new-profile ", "new profile "])
}
@@ -7,9 +7,9 @@ use crate::{
navigation::{
about_url, archive_idle_days, archive_url, bookmarks_url, downloads_url, history_url,
move_tab_space_name, new_private_profile_name, new_profile_name, new_space_name,
plugin_detail_url, plugins_url, reading_list_url, search_url, settings_page_url,
settings_url, shortcut_settings_url, space_icon, switch_profile_name, sync_status_url,
task_manager_url,
plugin_detail_url, plugins_url, reading_list_url, reading_progress_percent, search_url,
settings_page_url, settings_url, shortcut_settings_url, space_icon, switch_profile_name,
sync_status_url, task_manager_url,
},
};
@@ -123,6 +123,10 @@ impl BrowserCore {
self.archive_idle_tabs(SystemTime::now())?;
return Ok(true);
}
if let Some(percent) = reading_progress_percent(command)? {
self.set_active_tab_reading_progress(percent)?;
return Ok(true);
}
match command.to_ascii_lowercase().as_str() {
"new-tab" => {
@@ -1,6 +1,8 @@
use std::time::SystemTime;
use ely_domain::{ReadingListEntry, ReadingListId, ReadingProgress, UrlText};
use ely_domain::{
ReadingListEntry, ReadingListId, ReadingProgress, ReadingProgressPercent, UrlText,
};
use crate::CoreError;
@@ -36,6 +38,15 @@ impl BrowserCore {
Ok(())
}
pub fn set_active_tab_reading_progress(
&mut self,
percent: ReadingProgressPercent,
) -> Result<ReadingListId, CoreError> {
let entry_id = self.save_active_tab_to_reading_list()?;
self.set_reading_list_progress(&entry_id, ReadingProgress::InProgress(percent))?;
Ok(entry_id)
}
pub fn remove_reading_list_entry(&mut self, entry_id: &ReadingListId) -> Result<(), CoreError> {
let index = self.reading_list_entry_index(entry_id)?;
self.reading_list.remove(index);
+68 -2
View File
@@ -1,8 +1,9 @@
use std::error::Error;
use ely_browser_core::{BrowserCore, InitialBrowserConfig};
use ely_browser_core::{BrowserCore, CoreError, InitialBrowserConfig};
use ely_domain::{
CommandIntent, CommandScope, ProfileKind, ReadingListId, ReadingProgress, UrlText,
CommandIntent, CommandScope, DomainError, ProfileKind, ReadingListId, ReadingProgress,
ReadingProgressPercent, UrlText,
};
#[test]
@@ -49,6 +50,18 @@ fn reading_list_progress_updates_entry() -> Result<(), Box<dyn Error>> {
core.open_tab(UrlText::parse("https://example.com/long-read")?);
let entry_id = core.save_active_tab_to_reading_list()?;
core.set_reading_list_progress(
&entry_id,
ReadingProgress::InProgress(ReadingProgressPercent::new(42)?),
)?;
let snapshot = core.snapshot()?;
assert_eq!(snapshot.reading_list[0].id(), &entry_id);
assert_eq!(
snapshot.reading_list[0].progress(),
&ReadingProgress::InProgress(ReadingProgressPercent::new(42)?)
);
core.set_reading_list_progress(&entry_id, ReadingProgress::Finished)?;
let snapshot = core.snapshot()?;
@@ -57,6 +70,59 @@ fn reading_list_progress_updates_entry() -> Result<(), Box<dyn Error>> {
Ok(())
}
#[test]
fn active_tab_reading_progress_saves_partial_progress() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
core.open_tab(UrlText::parse("https://example.com/long-read")?);
let entry_id = core.set_active_tab_reading_progress(ReadingProgressPercent::new(47)?)?;
let snapshot = core.snapshot()?;
assert_eq!(snapshot.reading_list.len(), 1);
assert_eq!(snapshot.reading_list[0].id(), &entry_id);
assert_eq!(
snapshot.reading_list[0].progress(),
&ReadingProgress::InProgress(ReadingProgressPercent::new(47)?)
);
Ok(())
}
#[test]
fn reading_progress_command_updates_active_page_entry() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
core.open_tab(UrlText::parse("https://example.com/long-read")?);
core.set_command_query(">reading-progress 42%");
let intent = core.submit_command()?;
let snapshot = core.snapshot()?;
assert_eq!(intent, Some(CommandIntent::Command("reading-progress 42%".to_string())));
assert_eq!(snapshot.command_query, "");
assert_eq!(snapshot.reading_list.len(), 1);
assert_eq!(
snapshot.reading_list[0].progress(),
&ReadingProgress::InProgress(ReadingProgressPercent::new(42)?)
);
Ok(())
}
#[test]
fn reading_progress_command_rejects_terminal_percent() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
core.open_tab(UrlText::parse("https://example.com/long-read")?);
core.set_command_query(">reading-progress 100");
let Err(error) = core.submit_command() else {
return Err("expected invalid reading progress error".into());
};
assert_eq!(
error,
CoreError::Domain(DomainError::InvalidReadingProgressPercent { value: "100".to_string() })
);
Ok(())
}
#[test]
fn missing_reading_list_progress_update_returns_error() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;