5.5 KiB
5.5 KiB
ePub Reader — Design Document
Overview
A lightweight ePub reader desktop application built with Rust + egui, compiled as a single Windows executable (x86_64-pc-windows-gnu / MSYS2+MinGW). No console window. Built-in Chinese font support. Kindle-like reading experience with medium feature set.
Tech Stack
| Layer | Choice |
|---|---|
| GUI Framework | eframe (egui official framework) |
| Rendering Backend | wgpu |
| ePub Parsing | epub-rs |
| Font | Bundled Noto Sans SC (or similar open-source Chinese font) |
| Build Target | x86_64-pc-windows-gnu |
| Binary | Single .exe, #![windows_subsystem = "windows"] |
Core Data Model
struct AppState {
book: Option<Book>,
current_section: usize,
current_page: usize,
settings: Settings,
bookmarks: Vec<Bookmark>,
sidebar_open: bool,
}
struct Book {
title: String,
author: String,
cover: Option<Vec<u8>>,
sections: Vec<Section>,
toc: Vec<TocEntry>,
}
struct Section {
title: String,
content: String, // plain text (HTML tags stripped)
pages: Vec<usize>, // character offsets for page boundaries
}
struct Settings {
font_size: f32, // default 20.0
theme: Theme,
}
enum Theme { Light, Dark }
struct Bookmark {
section: usize,
page: usize,
label: String,
timestamp: i64,
}
struct TocEntry {
label: String,
section: usize,
children: Vec<TocEntry>,
}
Architecture
┌──────────────────────────────────────────┐
│ eframe::App │
│ ┌──────────┐ ┌───────────────────────┐ │
│ │ WelcomePg │ │ ReadingView │ │
│ │ (no book) │ │ ├─ TopToolbar │ │
│ │ ──────── │ │ ├─ Sidebar (TOC) │ │
│ │ open btn │ │ ├─ TextArea │ │
│ │ recents │ │ └─ BottomProgressBar │ │
│ └──────────┘ └───────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ AppState │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────────────────────┘
UI Layout
Welcome Screen (no book open)
- Centered "Open ePub File" button
- Recently opened books list (read from settings file)
Reading Screen (Kindle-like)
- Top toolbar: back button, book title, font size controls, menu, bookmark toggle, theme toggle
- Left sidebar (collapsible): table of contents tree
- Center: text content area with pagination
- Click left 30% → prev page, right 30% → next page, center 40% → toggle toolbar visibility
- Keyboard: ← → for prev/next page
- Bottom bar: current chapter name, progress slider, page number indicator
Features (Medium Scope)
Core
- Open
.epubfile via native file dialog - Parse ePub (OPF manifest, NCX/TOC, Spine)
- Render chapter content with pagination
- Next/previous page navigation (click & keyboard)
- Table of contents sidebar with chapter navigation
- Remember last reading position (bookmark per file)
Settings & Display
- Font size adjustment (A⁺/A⁻)
- Light/Dark theme toggle
- Chinese font support (bundled Noto Sans SC)
Bookmarks
- Add/remove bookmarks at current page
- Bookmark list view
Persistence
settings.jsonsaves: font_size, theme, recent files, reading positions, bookmarks
Data Flow
- User clicks "Open" → native file dialog → select
.epub EpubLoaderreads zip, extracts OPF metadata, reads spine order, parses NCX for TOC- For each spine item: extract HTML content, strip tags → plain text stored in
Section.content - On section load: calculate pagination based on current font_size + panel width → store page offsets
- On page change: slice
Section.content[pages[current_page]..pages[current_page+1]]→ render to eguiLabel - On font_size change: recalculate all pagination for current section
- On theme toggle: switch
egui::Stylebetween light/dark visuals
Pagination Algorithm
fn paginate(text: &str, font_size: f32, panel_width: f32) -> Vec<usize>
chars_per_line = floor(panel_width / (font_size * 0.6))
lines_per_page = floor(panel_height / (font_size * 1.5))
chars_per_page = chars_per_line * lines_per_page
Iterate text, split at chars_per_page boundaries (prefer word/char boundaries)
File Storage
settings.json(next to exe OR in standard config dir)- font_size, theme
- recent_files: Vec<{path, title}>
- reading_positions: HashMap<path, {section, page}>
- bookmarks: HashMap<path, Vec>
- Last window size/position
Error Handling
- ePub parsing failure → show error dialog with message
- File not found (recent list) → remove from list silently
- Font loading failure → fall back to system monospace
- Settings file corruption → reset to defaults, log warning
Out of Scope (v1)
- Text search within book
- Highlighting / annotations
- Notes/export
- TTS
- Epub with complex CSS styling / reflowable layout math
- DRM-protected ePubs