feat: 实现 PDF 文档阅读功能
- 实现 DocumentEngine,支持 PDF/EPUB/MOBI/TXT/Markdown/代码文件格式 - 添加文档格式自动检测功能 - 实现文档渲染为 HTML - 实现全文搜索功能 - 添加 CLI/TUI 用户界面 - 修复 tracing-subscriber feature 依赖问题
This commit is contained in:
184
src/ui/mod.rs
184
src/ui/mod.rs
@@ -1,20 +1,182 @@
|
||||
//! UI 模块
|
||||
//!
|
||||
//! 使用 Dioxus 构建跨平台 UI
|
||||
//! ReadFlow 用户界面
|
||||
//!
|
||||
//! 当前版本使用 CLI/TUI 模式,后续可扩展为桌面 GUI
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::core::document::DocumentEngine;
|
||||
|
||||
pub fn run(config: Config) {
|
||||
println!("Starting UI with config: {:?}", config.theme);
|
||||
println!("╔══════════════════════════════════════╗");
|
||||
println!("║ ReadFlow v0.1.0 ║");
|
||||
println!("║ 面向开发者的文档阅读工具 ║");
|
||||
println!("╚══════════════════════════════════════╝");
|
||||
println!();
|
||||
println!("主题: {}", config.theme.mode);
|
||||
println!("默认格式: {}", config.reader.default_format);
|
||||
println!("书库路径: {}", config.storage.library_path);
|
||||
println!();
|
||||
|
||||
// 后续实现:Dioxus UI 启动
|
||||
// 示例:
|
||||
// dioxus::launch(App);
|
||||
// 检查命令行参数
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
|
||||
if args.len() < 2 {
|
||||
print_help();
|
||||
return;
|
||||
}
|
||||
|
||||
let command = &args[1];
|
||||
|
||||
match command.as_str() {
|
||||
"open" => {
|
||||
if args.len() < 3 {
|
||||
eprintln!("用法: readflow open <文件路径>");
|
||||
return;
|
||||
}
|
||||
open_document(&args[2]);
|
||||
}
|
||||
"search" => {
|
||||
if args.len() < 4 {
|
||||
eprintln!("用法: readflow search <文件路径> <关键词>");
|
||||
return;
|
||||
}
|
||||
search_document(&args[2], &args[3]);
|
||||
}
|
||||
"info" => {
|
||||
if args.len() < 3 {
|
||||
eprintln!("用法: readflow info <文件路径>");
|
||||
return;
|
||||
}
|
||||
show_document_info(&args[2]);
|
||||
}
|
||||
"help" | "--help" | "-h" => {
|
||||
print_help();
|
||||
}
|
||||
_ => {
|
||||
// 尝试直接打开文件
|
||||
open_document(&args[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 后续实现:Dioxus 组件
|
||||
// pub fn App(cx: Scope) -> Element {
|
||||
// cx.render(rsx! {
|
||||
// div { "Hello, ReadFlow!" }
|
||||
// })
|
||||
// }
|
||||
fn print_help() {
|
||||
println!("用法:");
|
||||
println!(" readflow <文件路径> 打开文档");
|
||||
println!(" readflow open <文件路径> 打开文档");
|
||||
println!(" readflow info <文件路径> 显示文档信息");
|
||||
println!(" readflow search <文件> <关键词> 搜索文档内容");
|
||||
println!();
|
||||
println!("支持格式: PDF, EPUB, MOBI, TXT, Markdown, 代码文件");
|
||||
}
|
||||
|
||||
fn open_document(path: &str) {
|
||||
println!("正在打开: {}", path);
|
||||
println!("{}", "-".repeat(50));
|
||||
|
||||
let engine = DocumentEngine::new();
|
||||
|
||||
match engine.open(path) {
|
||||
Ok(doc) => {
|
||||
println!("✅ 文档打开成功!");
|
||||
println!();
|
||||
println!("📖 {}", doc.title);
|
||||
println!("📄 格式: {:?}", doc.format);
|
||||
println!("📑 页数: {}", doc.metadata.page_count);
|
||||
println!("💾 大小: {} bytes", doc.metadata.file_size);
|
||||
println!();
|
||||
|
||||
// 渲染文档内容(简化版)
|
||||
match engine.render(&doc) {
|
||||
Ok(html) => {
|
||||
// 只显示前几行
|
||||
let preview: String = html.lines().take(20).collect();
|
||||
println!("预览:\n{}", preview);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("渲染失败: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("❌ 打开失败: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn search_document(path: &str, query: &str) {
|
||||
println!("在 {} 中搜索: {}", path, query);
|
||||
println!("{}", "-".repeat(50));
|
||||
|
||||
let engine = DocumentEngine::new();
|
||||
|
||||
let doc = match engine.open(path) {
|
||||
Ok(d) => d,
|
||||
Err(e) => {
|
||||
eprintln!("❌ 打开失败: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match engine.search(&doc, query) {
|
||||
Ok(results) => {
|
||||
println!("找到 {} 个结果:", results.len());
|
||||
println!();
|
||||
|
||||
for (i, result) in results.iter().take(10).enumerate() {
|
||||
println!("[{}.] 第 {} 页", i + 1, result.page);
|
||||
println!(" 上下文: ...{}...", result.context);
|
||||
println!();
|
||||
}
|
||||
|
||||
if results.len() > 10 {
|
||||
println!("... 还有 {} 个结果", results.len() - 10);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("❌ 搜索失败: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show_document_info(path: &str) {
|
||||
println!("文档信息: {}", path);
|
||||
println!("{}", "-".repeat(50));
|
||||
|
||||
let engine = DocumentEngine::new();
|
||||
|
||||
match engine.open(path) {
|
||||
Ok(doc) => {
|
||||
println!("标题: {}", doc.title);
|
||||
println!("路径: {}", doc.path);
|
||||
println!("格式: {:?}", doc.format);
|
||||
println!();
|
||||
println!("元数据:");
|
||||
println!(" 页数: {}", doc.metadata.page_count);
|
||||
println!(" 文件大小: {} bytes", doc.metadata.file_size);
|
||||
println!(" 作者: {:?}", doc.metadata.author);
|
||||
println!();
|
||||
|
||||
// 获取目录
|
||||
match engine.get_toc(&doc) {
|
||||
Ok(toc) => {
|
||||
if toc.is_empty() {
|
||||
println!("目录: (无)");
|
||||
} else {
|
||||
println!("目录:");
|
||||
for entry in toc {
|
||||
let indent = " ".repeat(entry.level);
|
||||
println!("{}{}. {}", indent, entry.page, entry.title);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("获取目录失败: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("❌ 获取信息失败: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user