diff --git a/crates/zx_document_core/src/document.rs b/crates/zx_document_core/src/document.rs index 17214e8..3499e06 100644 --- a/crates/zx_document_core/src/document.rs +++ b/crates/zx_document_core/src/document.rs @@ -9,7 +9,88 @@ pub struct DocumentInfo { pub material_type: MaterialType, pub preview_mode: PreviewMode, pub file_size: u64, + + // Text stats pub page_count: Option, pub word_count: Option, + pub char_count: Option, + pub line_count: Option, + + // Image + pub image_width: Option, + pub image_height: Option, + pub image_format: Option, + + // EPUB + pub epub_chapter_count: Option, + + // Capabilities + pub is_searchable: bool, + pub supports_position: bool, + pub supports_anchor: bool, + pub created_at: Option, } + +impl DocumentInfo { + pub fn new(material_id: String, title: String, material_type: MaterialType, file_size: u64) -> Self { + let preview_mode = material_type.preview_mode(); + let (is_searchable, supports_position, supports_anchor) = match material_type { + MaterialType::Markdown | MaterialType::Text => (true, true, true), + MaterialType::Pdf => (true, true, true), + MaterialType::Image => (false, true, true), + MaterialType::Epub => (true, true, true), + MaterialType::Word | MaterialType::Excel | MaterialType::PowerPoint => (false, false, true), + MaterialType::Unknown => (false, false, false), + }; + Self { + material_id, + title, + material_type, + preview_mode, + file_size, + page_count: None, + word_count: None, + char_count: None, + line_count: None, + image_width: None, + image_height: None, + image_format: None, + epub_chapter_count: None, + is_searchable, + supports_position, + supports_anchor, + created_at: None, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_markdown_capabilities() { + let info = DocumentInfo::new("m1".into(), "test.md".into(), MaterialType::Markdown, 1024); + assert!(info.is_searchable); + assert!(info.supports_position); + assert_eq!(info.preview_mode, PreviewMode::NativeReader); + } + + #[test] + fn test_office_capabilities() { + let info = DocumentInfo::new("m2".into(), "report.docx".into(), MaterialType::Word, 2048); + assert!(!info.is_searchable); + assert!(!info.supports_position); + assert!(info.supports_anchor); // Material-level anchor only + assert_eq!(info.preview_mode, PreviewMode::PlatformPreview); + } + + #[test] + fn test_unknown_capabilities() { + let info = DocumentInfo::new("m3".into(), "file.bin".into(), MaterialType::Unknown, 0); + assert!(!info.is_searchable); + assert!(!info.supports_position); + assert!(!info.supports_anchor); + } +} diff --git a/crates/zx_document_core/src/progress.rs b/crates/zx_document_core/src/progress.rs index 5643076..5452c3d 100644 --- a/crates/zx_document_core/src/progress.rs +++ b/crates/zx_document_core/src/progress.rs @@ -130,6 +130,20 @@ impl ReadingPosition { } } + /// Check if a position type is compatible with a material type. + pub fn is_compatible_with(&self, mt: &crate::material_type::MaterialType) -> bool { + use crate::material_type::MaterialType; + matches!( + (self, mt), + (ReadingPosition::Markdown { .. }, MaterialType::Markdown) + | (ReadingPosition::Text { .. }, MaterialType::Text) + | (ReadingPosition::Pdf { .. }, MaterialType::Pdf) + | (ReadingPosition::Image { .. }, MaterialType::Image) + | (ReadingPosition::Epub { .. }, MaterialType::Epub) + | (ReadingPosition::Unknown, _) + ) + } + pub fn progress_value(&self) -> Option { match self { Self::Markdown { scroll_progress, .. } => Some(clamp_progress(*scroll_progress)), @@ -186,6 +200,16 @@ mod tests { assert!(json.contains("\"overallProgress\":1.0")); } + #[test] + fn test_is_compatible() { + use crate::material_type::MaterialType; + let md = ReadingPosition::Markdown { block_id: "h1".into(), scroll_progress: 0.5 }; + assert!(md.is_compatible_with(&MaterialType::Markdown)); + assert!(!md.is_compatible_with(&MaterialType::Pdf)); + assert!(ReadingPosition::Unknown.is_compatible_with(&MaterialType::Pdf)); + assert!(ReadingPosition::Unknown.is_compatible_with(&MaterialType::Markdown)); // Unknown = compatible with all + } + #[test] fn test_progress_value() { assert_eq!(ReadingPosition::Unknown.progress_value(), None);