use dirs::config_dir;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use std::fs;
use std::path::PathBuf;
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct BookProgress {
pub current_chapter: usize,
pub chapter_scrolls: HashMap<usize, usize>,
#[serde(default)]
pub title: String,
#[serde(default)]
pub author: String,
#[serde(default)]
pub path: String,
#[serde(default)]
pub last_read: u64,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct ProgressStore {
pub books: HashMap<String, BookProgress>,
pub last_book_path: Option<String>,
}
impl ProgressStore {
pub fn load() -> Self {
let path = Self::get_path();
if let Ok(content) = fs::read_to_string(path) {
serde_json::from_str(&content).unwrap_or_default()
} else {
ProgressStore::default()
}
}
pub fn save(&self) -> Result<(), Box<dyn Error>> {
let path = Self::get_path();
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
let content = serde_json::to_string_pretty(self)?;
fs::write(path, content)?;
Ok(())
}
fn get_path() -> PathBuf {
let mut path = config_dir().unwrap_or_else(|| PathBuf::from("."));
path.push("changxi");
path.push("progress.json");
path
}
pub fn get_book(&self, book_id: &str) -> BookProgress {
self.books.get(book_id).cloned().unwrap_or_default()
}
pub fn set_book(&mut self, book_id: String, progress: BookProgress) {
self.books.insert(book_id, progress);
}
pub fn remove_book(&mut self, title: &str, author: &str) {
let book_id = self
.books
.iter()
.find(|(_, b)| b.title == title && b.author == author)
.map(|(id, _)| id.clone());
if let Some(id) = book_id {
self.books.remove(&id);
}
}
}