use serde::{Deserialize, Serialize}; use crate::error::DocumentError; use crate::material_type::MaterialType; /// Describes how an Office document should be previewed. /// /// - Word/Excel → PlatformPreview (iOS: QLPreviewController / WKWebView) /// - PowerPoint → ExternalOpen (open in system app) /// - Future: ServerConvertedPdf (server converts Office→PDF) #[derive(Debug, Clone, Serialize, Deserialize, uniffi::Enum)] pub enum OfficePreviewStrategy { /// Use OS-native preview (QLPreviewController on iOS, Intent on Android) PlatformPreview, /// Open in external app (e.g., PowerPoint app for .pptx) ExternalOpen, /// Server-side conversion to PDF, then preview the PDF ServerConvertedPdf, /// Format not supported for preview Unsupported, } /// Preview configuration for an Office document. #[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)] pub struct OfficePreviewConfig { pub material_type: MaterialType, pub strategy: OfficePreviewStrategy, pub file_size: u64, /// Whether the document can be searched after server conversion pub supports_search_after_conversion: bool, } /// Get the recommended preview strategy for an Office material type. pub fn get_office_preview_config( material_type: &MaterialType, file_size: u64, ) -> Result { let (strategy, supports_search) = match material_type { MaterialType::Word | MaterialType::Excel => { (OfficePreviewStrategy::PlatformPreview, true) } MaterialType::PowerPoint => { (OfficePreviewStrategy::ExternalOpen, true) } _ => { return Err(DocumentError::UnsupportedFormat( "not an Office document type".into() )); } }; Ok(OfficePreviewConfig { material_type: material_type.clone(), strategy, file_size, supports_search_after_conversion: supports_search, }) } /// Check if a material type is an Office document. pub fn is_office_type(mt: &MaterialType) -> bool { matches!( mt, MaterialType::Word | MaterialType::Excel | MaterialType::PowerPoint ) } #[cfg(test)] mod tests { use super::*; #[test] fn test_word_preview_strategy() { let config = get_office_preview_config(&MaterialType::Word, 1024).unwrap(); assert!(matches!(config.strategy, OfficePreviewStrategy::PlatformPreview)); assert!(config.supports_search_after_conversion); } #[test] fn test_excel_preview_strategy() { let config = get_office_preview_config(&MaterialType::Excel, 2048).unwrap(); assert!(matches!(config.strategy, OfficePreviewStrategy::PlatformPreview)); } #[test] fn test_powerpoint_preview_strategy() { let config = get_office_preview_config(&MaterialType::PowerPoint, 512).unwrap(); assert!(matches!(config.strategy, OfficePreviewStrategy::ExternalOpen)); } #[test] fn test_non_office_rejected() { assert!(get_office_preview_config(&MaterialType::Markdown, 100).is_err()); assert!(get_office_preview_config(&MaterialType::Pdf, 100).is_err()); } #[test] fn test_is_office_type() { assert!(is_office_type(&MaterialType::Word)); assert!(is_office_type(&MaterialType::Excel)); assert!(is_office_type(&MaterialType::PowerPoint)); assert!(!is_office_type(&MaterialType::Pdf)); assert!(!is_office_type(&MaterialType::Markdown)); } }