35 KiB
E-Reader Application Requirements
Overview
This document defines the requirements for a full-featured e-reader application built on the dreader/pyWebLayout framework. The application will support multiple modes, state persistence, and a complete user interaction model.
Implementation Status Summary
Legend
- ✅ Complete: Fully implemented and tested
- 📖 Example Ready: Working examples exist, needs production controller
- 🔜 Planned: Designed but not yet implemented
- ⏸️ Future: Deferred to later phase
Core Features Status
| Feature | Status | Location |
|---|---|---|
| EbookReader (page rendering, navigation) | ✅ Complete | application.py |
| Gesture handling (tap, swipe, pinch) | ✅ Complete | gesture.py |
| Navigation Overlay (unified TOC + Bookmarks) | ✅ Complete | application.py, examples/navigation_overlay_example.py |
| Settings Overlay | ✅ Complete | application.py |
| Highlighting system | ✅ Complete | application.py |
| Library management | ✅ Complete | library.py |
| State persistence | ✅ Complete | state.py |
| Persistent rendering settings | ✅ Complete | examples/persistent_settings_example.py |
| Book scanning & metadata | ✅ Complete | book_utils.py |
| Mode transitions (LIBRARY ↔ READING) | 📖 Example Ready | examples/library_reading_integration.py |
| Full application integration | 📖 Example Ready | All components working, needs main controller |
| Word Lookup Overlay | 🔜 Spec complete | Phase 2 |
| X-Ray feature | 🔜 Spec complete | Phase 2 |
Phase Completion
- Phase 1 (MVP): ~95% complete - All core features working with examples, needs production main controller
- Phase 2: ~60% complete - Unified navigation overlay done, settings persistence complete, word lookup planned
- Phase 3: 0% complete - Advanced features deferred
Working Examples
The following complete, runnable examples demonstrate full integration:
| Example | Demonstrates | Status |
|---|---|---|
| simple_ereader_example.py | Basic reading, page navigation, bookmarks | ✅ Working |
| library_reading_integration.py | Full LIBRARY ↔ READING workflow | ✅ Working |
| persistent_settings_example.py | Settings persistence across sessions | ✅ Working |
| navigation_overlay_example.py | Unified navigation with tabs | ✅ Working |
| demo_settings_overlay.py | Settings overlay interactions | ✅ Working |
| word_selection_highlighting.py | Text highlighting | ✅ Working |
Key Integration Example: library_reading_integration.py demonstrates the complete user flow:
- Display library of EPUB files
- Select book by clicking/tapping
- Open and read selected book
- Access settings overlay
- Return to library from settings
- Select another book
- Auto-resume from saved position
1. Application Modes
1.1 LIBRARY Mode ✅ (Implemented in library.py)
Purpose: Browse and select books from the user's library
Features:
- Display grid/table of available books with cover images
- Show book metadata (title, author)
- Book selection via touch/click
- Visual feedback on selection (highlight, hover state)
- Support for scrolling/pagination if library is large
- Search/filter books (future enhancement)
- Sort options (by title, author, recent, etc.) (future enhancement)
Interactions:
- Tap/Click on book: Transition to READING mode with selected book
- Long-press on book: Show book context menu (delete, info, etc.) (future)
- Swipe: Scroll library view
Display Requirements:
- Cover images: 150-300px wide thumbnails
- Title/Author text below or beside cover
- Responsive layout for different screen sizes
- Loading indicator while scanning library
1.2 READING Mode ✅ (Implemented in application.py)
Purpose: Read the current book with page navigation
Features:
- Display current page rendered by pyWebLayout
- Page navigation (next/previous)
- Access to overlays via buttons/gestures
- Visual progress indicator (page numbers, percentage)
- Header showing book title/author
- Footer with navigation controls
Interactions:
- Tap left/right edge: Previous/Next page
- Swipe left/right: Previous/Next page
- Tap center: Toggle controls visibility (future)
- Tap header buttons: Open overlays (TOC, Settings, etc.)
- Pinch in/out: Decrease/Increase font size
- Long-press on word: Show definition/highlight menu (future)
Sub-states within READING mode:
- Base reading state: Just the page content
- TOC_OVERLAY: Table of contents over page
- SETTINGS_OVERLAY: Settings panel over page
- BOOKMARKS_OVERLAY: Bookmarks list over page
1.3 Overlay States
1.3.1 TOC_OVERLAY ✅ (Implemented)
Purpose: Navigate to different chapters
Features:
- Scrollable list of chapters
- Hierarchical chapter display (if available)
- Current chapter indication
- Click to jump to chapter
Interactions:
- Tap chapter: Jump to chapter, close overlay, return to READING
- Tap close/back: Return to READING mode
- Tap outside overlay: Close overlay (optional)
1.3.2 SETTINGS_OVERLAY ✅ (Implemented)
Purpose: Adjust reading preferences
Features:
- Font size controls (A-, A+)
- Line spacing controls
- Brightness controls (if hardware supports)
- Theme selection (day/night/sepia) (future)
- WiFi configuration (future)
Interactions:
- Tap buttons: Adjust settings in real-time
- Tap close: Return to READING mode
- Changes persist across sessions
1.3.3 BOOKMARKS_OVERLAY ✅ (Implemented)
Purpose: Manage and navigate bookmarks
Features:
- List of saved bookmarks with names
- Show bookmark position info (chapter, page)
- Delete bookmark option
- Add new bookmark option
Interactions:
- Tap bookmark: Jump to bookmark, close overlay, return to READING
- Tap delete: Remove bookmark from list
- Tap close: Return to READING mode
1.3.4 WORD_LOOKUP_OVERLAY 🔜 (Planned for Phase 2)
Purpose: Provide word definitions and contextual analysis
Features:
- Dictionary Lookup: Show word definition, pronunciation, etymology
- X-Ray Feature: Display LLM-generated contextual information about characters, places, and concepts
- Show spoiler-free summary of what has been revealed about this entity up to current reading position
- Character information: relationships, motivations, key events involving them (up to current page only)
- Place information: descriptions, significance, events that occurred there (up to current page only)
- Concept information: explanations, thematic importance (up to current page only)
- Pre-generated per book via LLM analysis (offline process), stored in cache
- Never reveals information from future chapters
- Highlight Options: Add permanent highlight to selected word with color choice
- Copy to Clipboard: Copy word or selection
Interactions:
- Tap "Dictionary": Show dictionary definition panel
- Tap "X-Ray": Show spoiler-free contextual summary (if available for this entity)
- Tap "Highlight": Add colored highlight, show color picker
- Tap "Copy": Copy text to clipboard
- Tap close/outside: Return to READING mode
Display Layout:
┌─────────────────────────────────────┐
│ Selected: "Sherlock Holmes" │
├─────────────────────────────────────┤
│ [Dictionary] [X-Ray] [Highlight] │
├─────────────────────────────────────┤
│ (Content area based on active tab) │
│ │
│ Dictionary Tab: │
│ Definition, pronunciation, etc. │
│ │
│ X-Ray Tab: │
│ SHERLOCK HOLMES (Character) │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ A consulting detective living in │
│ London at 221B Baker Street. Known │
│ for exceptional deductive reasoning│
│ and observational skills. │
│ │
│ Key Relationships (so far): │
│ • Dr. Watson - Companion, narrator │
│ • Mrs. Hudson - Landlady │
│ │
│ Mentioned: 23 times (Chapters 1-3) │
│ [Info current as of your position] │
└─────────────────────────────────────┘
Data Requirements:
- X-Ray data file per book (JSON format)
- Generated via LLM chapter-by-chapter analysis (offline process)
- Structure:
{entity_name: {chapter_N: {summary, relationships, ...}}} - Lookup uses current reading position to filter out future content
- Dictionary API integration (local or online)
- Entity recognition (match selected word to X-Ray entities)
2. State Management & Persistence ✅ (Implemented in state.py)
2.1 State Definition
The application must track and persist the following state:
class EreaderMode(Enum):
LIBRARY = "library"
READING = "reading"
class OverlayState(Enum):
NONE = "none"
TOC = "toc"
SETTINGS = "settings"
BOOKMARKS = "bookmarks"
WORD_LOOKUP = "word_lookup"
2.2 Persistent State Data Structure
Key Insight: EbookReader already manages bookmarks and positions via bookmarks_dir. Our state only needs to track high-level application state, not page positions.
{
"version": "1.0",
"mode": "reading",
"overlay": "none",
"current_book": {
"path": "/path/to/book.epub",
"title": "Book Title",
"author": "Author Name",
"last_read_timestamp": "2025-11-07T10:30:00Z"
},
"library": {
"books_path": "/path/to/library",
"last_selected_index": 3,
"scan_cache": [
{
"path": "/path/to/book.epub",
"title": "Book Title",
"author": "Author",
"cover_cached": true,
"last_modified": "2025-11-01T12:00:00Z"
}
]
},
"settings": {
"font_scale": 1.0,
"line_spacing": 5,
"inter_block_spacing": 15,
"brightness": 8,
"theme": "day"
}
}
What's NOT in state (handled by EbookReader):
- Current page position →
EreaderLayoutManager.current_position - Bookmarks →
bookmarks_dir/{document_id}_{bookmark_name}.json - Reading progress → Calculated on-demand by
reader.get_reading_progress()
Auto-Resume Strategy:
- Use special bookmark name
"__auto_resume__"for last position - Bookmark files are per-book:
{document_id}___auto_resume__.json - On shutdown:
reader.save_position("__auto_resume__") - On startup:
reader.load_position("__auto_resume__") - No mixing between books (each has its own document_id)
2.3 State Persistence Requirements
- Location:
- Linux/Mac:
~/.config/dreader/state.json - Windows:
%APPDATA%/dreader/state.json
- Linux/Mac:
- Save Triggers:
- On mode change
- On page turn (debounced to avoid excessive writes)
- On settings change
- On bookmark add/delete
- On application close
- Load Triggers:
- On application startup
- After crash/power loss (automatic recovery)
- Safety:
- Atomic writes (write to temp file, then rename)
- Validation on load (schema check, corrupt data handling)
- Backup previous state file
- Handle missing/corrupt state gracefully
2.4 Boot/Resume Behavior
-
Cold Start (no state file):
- Start in LIBRARY mode
- Default settings applied
-
Resume from State:
- If last mode was LIBRARY: Return to library view
- If last mode was READING: Reopen last book at last page
- Restore all settings (font size, spacing, etc.)
- Clear overlay state (always start without overlay)
-
Error Handling:
- If last book no longer exists: Return to LIBRARY mode
- If state file corrupt: Start fresh, backup corrupt file
- Log all state errors for debugging
3. Interaction Model ✅ (Implemented via gesture.py + application.handle_touch)
3.1 Touch/Click Callbacks
The application must support callbacks/handlers for:
LIBRARY Mode:
on_book_selected(book_path)- Open book in READING modeon_library_scroll(direction)- Scroll library view
READING Mode:
on_page_turn(direction)- Next/Previous pageon_tap_region(x, y, region)- Handle tap on specific region- Regions: left-edge, right-edge, center, header, footer
on_button_press(button_id)- Handle button clicks- Buttons: toc, settings, bookmarks, library
on_zoom_gesture(direction)- Pinch in/out for font sizeon_word_tap(x, y)- Single tap on word for quick highlighton_word_long_press(x, y)- Long press on word for lookup overlay
Overlay Mode:
on_chapter_selected(chapter_index)- Jump to chapteron_setting_changed(setting_name, value)- Update settingson_bookmark_selected(bookmark_name)- Jump to bookmarkon_word_lookup_action(action, word)- Handle word lookup actions- Actions: dictionary, xray, highlight, copy
on_xray_occurrence_selected(position)- Jump to word occurrenceon_overlay_close()- Return to READING mode
3.2 Interactive Elements in Rendered Content
For the library view rendered via pyWebLayout:
- Each book cover/title should be a clickable element
- Use pyWebLayout's link/interactive features to make covers tappable
- Query pixel coordinates to determine which book was clicked
- Map clicks to book indices
Implementation Options:
- Bounding Box Approach: Store bounding boxes for each book element, detect clicks
- HTML Links: Embed book paths as links in HTML, use link query API
- Table Cell IDs: Use table cell metadata to identify clicked books
4. Library Management ✅ (Implemented in book_utils.py + library.py)
4.1 Book Scanning
- Scan specified directory for EPUB files
- Extract metadata (title, author) using pyWebLayout's EPUB reader
- Extract cover images (or use first page as fallback)
- Cache metadata to avoid re-scanning on every boot
- Support for incremental updates (only scan new/modified files)
4.2 Cover Image Handling
Options:
- Base64 Embedded: Encode covers as base64 in HTML (current approach)
- File-based: Save covers to cache directory, reference by path
- Hybrid: Cache on disk, fall back to base64 for generation
Recommendation: File-based caching
- Faster page generation
- Less memory usage
- Reusable across sessions
4.3 Library Cache Structure
~/.config/dreader/
├── state.json # Application state
├── covers/ # Cached cover images
│ ├── book1_cover.png
│ ├── book2_cover.png
│ └── ...
├── bookmarks/ # Bookmark data per book
│ ├── book1.json
│ └── book2.json
├── highlights/ # Highlight data per book
│ ├── book1.json
│ └── book2.json
└── xray/ # X-Ray data per book (LLM-generated)
├── book1_xray.json
└── book2_xray.json
X-Ray Data Format Example:
{
"version": "1.0",
"book_id": "sherlock_holmes_adventures",
"generated_date": "2025-11-08",
"entities": {
"Sherlock Holmes": {
"type": "character",
"chapters": {
"1": {
"summary": "Introduced as a consulting detective...",
"relationships": ["Dr. Watson"],
"traits": ["observant", "logical"],
"key_events": ["Met Watson", "Moved to Baker Street"]
},
"2": {
"summary": "Demonstrates deductive method...",
"relationships": ["Dr. Watson", "Inspector Lestrade"],
"traits": ["observant", "logical", "unconventional"],
"key_events": ["Solved first case"]
}
}
},
"221B Baker Street": {
"type": "place",
"chapters": {
"1": {
"summary": "Holmes and Watson's shared lodgings",
"significance": "Home base for investigations"
}
}
}
}
}
5. Technical Architecture ✅ (Core modules implemented)
5.1 Module Structure
dreader/
├── __init__.py # ✅ Exports
├── application.py # ✅ EbookReader class with gesture handling
├── state.py # ✅ State management with asyncio auto-save
├── library.py # ✅ Library mode logic with interactive selection
├── book_utils.py # ✅ Book scanning utilities
├── html_generator.py # ✅ HTML generation for UI
├── gesture.py # ✅ Touch/gesture event handling
└── overlay.py # ✅ Overlay rendering and compositing
Note: No separate callbacks.py - gesture handling integrated into application.py via handle_touch() method
5.2 State Manager API (dreader/state.py)
class StateManager:
def __init__(self, state_file_path: str)
def load_state() -> AppState
def save_state(state: AppState)
def get_current_mode() -> EreaderMode
def set_mode(mode: EreaderMode)
def get_current_book() -> Optional[BookState]
def set_current_book(book: BookState)
def get_settings() -> Settings
def update_setting(key: str, value: Any)
5.3 Library Manager API (dreader/library.py)
class LibraryManager:
def __init__(self, library_path: str, cache_dir: str)
def scan_library() -> List[Book]
def get_cached_metadata() -> List[Book]
def refresh_metadata(book_path: str)
def get_book_at_index(index: int) -> Optional[Book]
def render_library_view() -> Image.Image
def handle_library_click(x: int, y: int) -> Optional[str] # Returns book path
5.4 Callback Manager API (dreader/callbacks.py)
class CallbackManager:
def __init__(self, reader: EbookReader, state_manager: StateManager, library_manager: LibraryManager)
def handle_interaction(event: InteractionEvent) -> Response
def on_book_selected(book_path: str)
def on_page_turn(direction: str)
def on_overlay_open(overlay_type: OverlayState)
def on_overlay_close()
def on_settings_change(setting: str, value: Any)
6. HAL (Hardware Abstraction Layer) Integration
6.1 HAL Responsibilities
The HAL will handle:
- Rendering images to the display
- Capturing touch/click input
- Sending interaction events to the application
- Hardware-specific features (brightness control, WiFi, etc.)
6.2 Application ↔ HAL Interface
From Application to HAL:
render_image(image: PIL.Image, layer: str)- Display image on specified layer- Layers: "base" (page/library), "overlay" (settings/TOC/etc.)
set_brightness(level: int)- Adjust screen brightnessshow_loading(message: str)- Display loading indicator
From HAL to Application:
on_touch(x: int, y: int, gesture: GestureType)- Touch eventon_button_press(button_id: str)- Hardware button press (if any)on_power_event(event: PowerEvent)- Sleep/wake/shutdown
6.3 Multi-Layer Rendering
To support overlays efficiently:
- Base Layer: Main content (library view or reading page)
- Overlay Layer: Semi-transparent overlays (TOC, settings, etc.)
- HAL Compositing: HAL combines layers for display
Alternative: Application composites layers and sends single image to HAL
7. Future Enhancements
7.1 Phase 2 Features
- Full-text search within books
- ✅ Highlighting and annotations (basic implementation exists)
- Word lookup overlay with dictionary and X-Ray features
- Night/sepia reading themes
- WiFi configuration UI
- OTA (over-the-air) updates
- Cloud sync for bookmarks/progress
- PDF support
7.2 Phase 3 Features
- Multiple library folders
- Collections/categories
- Reading statistics
- Social features (sharing quotes, etc.)
- Text-to-speech
- Translation support
8. Testing Requirements
8.1 Unit Tests
- State serialization/deserialization
- State file corruption handling
- Library scanning with various EPUB formats
- Callback routing logic
- Click detection and bounding box calculations
8.2 Integration Tests
- Full mode transitions (LIBRARY → READING → OVERLAY → READING → LIBRARY)
- State persistence across "reboots" (save → load → verify)
- Multi-book workflow (open book A, switch to book B, resume book A)
- Settings changes reflected in rendering
8.3 Manual/UI Tests
- Touch responsiveness on target hardware
- Overlay appearance and dismissal
- Page turn performance
- Library scrolling smoothness
- Boot time from power-on to usable state
9. Performance Requirements
- Boot Time: < 3 seconds to display library or resume reading
- Page Turn: < 200ms from gesture to new page display
- Library Load: < 1 second for libraries up to 100 books
- State Save: < 50ms (non-blocking if possible)
- Memory: < 100MB RAM for typical book (depends on images)
10. Implementation Priority
Phase 1 (MVP):
- ✅ Basic EbookReader class (application.py - complete)
- ✅ HTML generation for reading view (html_generator.py - complete)
- ✅ Book scanning and metadata extraction (book_utils.py - complete)
- ✅ State management module with persistence (state.py - complete)
- ✅ Library manager with clickable book selection (library.py - complete)
- ✅ Mode transitions (LIBRARY ↔ READING) - FULLY DEMONSTRATED in examples/library_reading_integration.py
- ✅ Basic overlays (TOC, Settings) - overlay.py + application.py methods complete
- ✅ Gesture/touch handling (gesture.py - complete with TouchEvent, GestureType, GestureResponse)
- ✅ Full application integration - WORKING EXAMPLES EXIST, needs production main.py controller
Phase 2:
- ✅ Bookmarks overlay with management (application.py:1351-1377 - complete)
- ✅ Settings persistence and real-time updates (FULLY COMPLETE)
- ✅ Settings overlay with real-time preview (application.py:1318-1349)
- ✅ Settings saved to state.json (state.py:79-103)
- ✅ Settings restored on app startup via apply_settings() (application.py:725-765)
- ✅ Includes: font_scale, line_spacing, inter_block_spacing, word_spacing
- ✅ Example: examples/persistent_settings_example.py
- ✅ Boot recovery and resume functionality (FULLY TESTED)
- ✅ Position restoration via auto_resume bookmark (tests/test_boot_recovery.py:49-98)
- ✅ Settings restoration across sessions (tests/test_boot_recovery.py:100-153)
- ✅ Bookmark persistence (tests/test_boot_recovery.py:155-200)
- ✅ Full state workflow (tests/test_boot_recovery.py:202-277)
- ✅ Multiple books with separate state (tests/test_boot_recovery.py:279-343)
- ✅ Corrupt state file recovery (tests/test_boot_recovery.py:345-362)
- ✅ Missing book handling (tests/test_boot_recovery.py:364-393)
- ✅ Cold start with no state (tests/test_boot_recovery.py:395-414)
- ✅ Async auto-save functionality (tests/test_boot_recovery.py:516-586)
- 🚧 Error handling and user feedback
- 🚧 Performance optimization
- 🔜 Word lookup overlay (Dictionary + X-Ray feature) - spec complete, not implemented
- ✅ Unified navigation overlay (TOC + Bookmarks tabs) - COMPLETE
- ✅ Tabbed interface combining Contents and Bookmarks (html_generator.py:507-637)
- ✅ Tab switching without closing overlay (overlay.py:459-481, application.py:1172-1186)
- ✅ Gesture handling for all interactions (application.py:828-904)
- ✅ New OverlayState.NAVIGATION state (state.py:33)
- ✅ Tests and example provided (tests/test_navigation_overlay.py, examples/navigation_overlay_example.py)
- ✅ Documentation: NAVIGATION_OVERLAY_IMPLEMENTATION.md
Phase 3:
- Advanced library features (search, sort, filter)
- Advanced highlighting (color picker, annotation notes)
- Enhanced X-Ray (character relationships, concept maps)
- Themes and customization
- Offline dictionary database
- Word history and vocabulary tracking
Resolved Design Decisions
1. Click Detection in Library View ✓
Decision: Use pyWebLayout's built-in is_interactive and link_target properties
- Each book element is marked as interactive with book path as link_target
- Query pixel on tap to get clicked book
- Same pattern as in-book link handling (application.py:748-769)
2. Multi-Layer Rendering ✓
Decision: Application-side compositing
- Application renders base layer (library or reading page)
- For overlays: Composite smaller overlay image onto base layer
- Remove overlay by re-rendering the existing base page
- On settings change: Re-render background, then re-composite overlay if active
- Single final image sent to HAL for display
3. State Save Frequency ✓
Decision: Timer-based with asyncio
- Auto-save every 60 seconds (configurable)
- Immediate save on:
- Book closed
- Device shutdown
- Mode change
- Settings change
- Use asyncio timer loop for automatic saves (non-blocking)
4. Cover Image Strategy
Decision: File-based cache (preferred)
- Cache covers to
~/.config/dreader/covers/ - Generate on first scan, reuse on subsequent boots
- Fallback to base64 if cache unavailable
5. HAL Integration
Decision: HAL provides gesture recognition
- HAL sends TouchEvent with GestureType (TAP, SWIPE, etc.)
- Application handles business logic via gesture handlers
- Application returns GestureResponse with action type
11. Main Application Controller (Final Integration Piece)
11.1 Current Status
All core components are fully functional and tested with working integration examples. What's needed is a production-ready main application controller to orchestrate these components.
11.2 Reference Implementation
The file examples/library_reading_integration.py demonstrates the complete integration pattern and serves as a reference for building the main controller.
11.3 Required Main Controller Components
A. Application Class Structure
class DReaderApplication:
"""
Main application controller coordinating library and reading modes.
Responsibilities:
- Mode management (LIBRARY ↔ READING transitions)
- Component lifecycle (LibraryManager, EbookReader)
- State persistence integration
- Event routing to appropriate handlers
- Display updates
"""
def __init__(self, config: AppConfig):
# State management
self.state_manager = StateManager()
self.state = self.state_manager.load_state()
# Components (lazy-initialized)
self.library: Optional[LibraryManager] = None
self.reader: Optional[EbookReader] = None
# Display abstraction
self.display_hal = config.display_hal
self.current_image: Optional[Image.Image] = None
def start(self):
"""Initialize and show initial screen based on saved state"""
def handle_touch(self, event: TouchEvent):
"""Route touch events to library or reader based on mode"""
def shutdown(self):
"""Clean shutdown with state preservation"""
B. Mode Transition Logic
def _enter_library_mode(self):
"""Switch to library browsing"""
# 1. Save and close reader if active
if self.reader:
self.reader.save_position("__auto_resume__")
self.reader.close()
self.reader = None
# 2. Initialize library
if not self.library:
self.library = LibraryManager(...)
# 3. Render library view
self.current_image = self.library.render_library()
self.state_manager.set_mode(EreaderMode.LIBRARY)
self._update_display()
def _enter_reading_mode(self, book_path: str):
"""Switch to reading mode"""
# 1. Initialize reader if needed
if not self.reader:
self.reader = EbookReader(...)
# 2. Load book
self.reader.load_epub(book_path)
# 3. Apply saved settings
self.reader.apply_settings(self.state.settings.to_dict())
# 4. Restore position
self.reader.load_position("__auto_resume__")
# 5. Update state
self.state_manager.set_current_book(BookState(...))
self.state_manager.set_mode(EreaderMode.READING)
# 6. Render page
self.current_image = self.reader.get_current_page()
self._update_display()
C. Event Handling Integration
def handle_touch(self, event: TouchEvent):
"""Process touch based on current mode"""
if self.state.mode == EreaderMode.LIBRARY:
self._handle_library_touch(event)
elif self.state.mode == EreaderMode.READING:
self._handle_reading_touch(event)
self._update_display()
def _handle_library_touch(self, event: TouchEvent):
"""Library mode touch handling"""
if event.gesture == GestureType.TAP:
book_path = self.library.handle_library_tap(event.x, event.y)
if book_path:
self._enter_reading_mode(book_path)
def _handle_reading_touch(self, event: TouchEvent):
"""Reading mode touch handling"""
response = self.reader.handle_touch(event)
# Handle special actions
if response.action == ActionType.BACK_TO_LIBRARY:
self._enter_library_mode()
elif response.action == ActionType.PAGE_TURN:
self.current_image = self.reader.get_current_page()
elif response.action == ActionType.OVERLAY_OPENED:
self.current_image = self.reader.get_current_page()
elif response.action == ActionType.SETTING_CHANGED:
# Settings changed, update state
settings = self.reader.get_current_settings()
self.state_manager.update_settings(settings)
D. State Persistence Integration
def start(self):
"""Boot sequence with state restoration"""
# 1. Start auto-save
self.state_manager.start_auto_save()
# 2. Restore previous mode
if self.state.mode == EreaderMode.READING and self.state.current_book:
# Resume reading last book
self._enter_reading_mode(self.state.current_book.path)
else:
# Show library
self._enter_library_mode()
# 3. Display initial screen
self._update_display()
def shutdown(self):
"""Graceful shutdown"""
# 1. Save current position if reading
if self.reader and self.reader.is_loaded():
self.reader.save_position("__auto_resume__")
self.reader.close()
# 2. Stop auto-save and save final state
asyncio.run(self.state_manager.stop_auto_save(save_final=True))
11.4 Display HAL Interface
The main controller needs a display abstraction layer (HAL). This is platform-specific and not part of the core dreader library.
Required HAL Interface:
class DisplayHAL(ABC):
"""Abstract display interface for platform integration"""
@abstractmethod
def show_image(self, image: Image.Image):
"""Display a PIL Image on the screen"""
@abstractmethod
def get_touch_events(self) -> Iterator[TouchEvent]:
"""Get iterator of touch events from hardware"""
@abstractmethod
def set_brightness(self, level: int):
"""Set display brightness (0-10)"""
Example Implementations:
- E-Ink Display: Use device-specific SDK (e.g., IT8951, Remarkable)
- Desktop Testing: Use PIL + tkinter or pygame
- Web Interface: Use Flask + HTML canvas
- Qt Application: Use QPixmap + QTouchEvent
11.5 Implementation Checklist
To complete the main application controller:
- Create
dreader/main.pywithDReaderApplicationclass - Implement mode transition methods (
_enter_library_mode,_enter_reading_mode) - Implement event routing (
handle_touch) - Implement boot/resume logic (
start) - Implement graceful shutdown (
shutdown) - Create platform-specific DisplayHAL implementation
- Create configuration system (AppConfig class)
- Add command-line argument parsing
- Create systemd service file (for embedded systems)
- Add logging throughout controller
- Write integration tests for main controller
- Create user documentation
11.6 Platform-Specific Entry Points
Once the main controller exists, create platform-specific entry points:
Desktop (Pygame):
# desktop_app.py
from dreader.main import DReaderApplication
from hal.pygame_display import PygameDisplayHAL
def main():
config = AppConfig(
display_hal=PygameDisplayHAL(width=800, height=1200),
library_path="~/Books",
page_size=(800, 1200)
)
app = DReaderApplication(config)
app.start()
# Event loop
running = True
while running:
for event in app.display_hal.get_touch_events():
app.handle_touch(event)
app.shutdown()
E-Ink Device:
# eink_app.py
from dreader.main import DReaderApplication
from hal.eink_display import EinkDisplayHAL
def main():
config = AppConfig(
display_hal=EinkDisplayHAL(device="/dev/epd"),
library_path="/mnt/books",
page_size=(1200, 1600)
)
app = DReaderApplication(config)
app.start()
# Hardware event loop
app.display_hal.run_event_loop(app.handle_touch)
app.shutdown()
Web Interface:
# web_app.py
from flask import Flask, render_template, jsonify, request
from dreader.main import DReaderApplication
from hal.web_display import WebDisplayHAL
app = DReaderApplication(...)
@app.route('/touch', methods=['POST'])
def handle_touch():
x, y = request.json['x'], request.json['y']
gesture = request.json['gesture']
event = TouchEvent(gesture, x, y)
app.handle_touch(event)
return jsonify(success=True)
@app.route('/current_image')
def get_image():
return send_image(app.current_image)
Acceptance Criteria
The implementation is complete when:
- User can browse library and select a book with a single tap
- Selected book opens at last read position (or first page if new)
- User can turn pages forward/backward via tap or swipe
- User can open TOC and jump to any chapter
- User can adjust font size and see changes immediately
- User can add/remove bookmarks and navigate to them
- Application state persists across reboots
- Application resumes exactly where user left off after power cycle
- All features work on target hardware with acceptable performance
- No data loss on unexpected shutdown/crash