# 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](dreader/application.py) | | Gesture handling (tap, swipe, pinch) | βœ… Complete | [gesture.py](dreader/gesture.py) | | Navigation Overlay (unified TOC + Bookmarks) | βœ… Complete | [application.py](dreader/application.py), [examples/navigation_overlay_example.py](examples/navigation_overlay_example.py) | | Settings Overlay | βœ… Complete | [application.py](dreader/application.py#L1318-L1349) | | Highlighting system | βœ… Complete | [application.py](dreader/application.py#L1086-L1288) | | Library management | βœ… Complete | [library.py](dreader/library.py) | | State persistence | βœ… Complete | [state.py](dreader/state.py) | | Persistent rendering settings | βœ… Complete | [examples/persistent_settings_example.py](examples/persistent_settings_example.py) | | Book scanning & metadata | βœ… Complete | [book_utils.py](dreader/book_utils.py) | | Mode transitions (LIBRARY ↔ READING) | πŸ“– Example Ready | [examples/library_reading_integration.py](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](examples/simple_ereader_example.py) | Basic reading, page navigation, bookmarks | βœ… Working | | [library_reading_integration.py](examples/library_reading_integration.py) | **Full LIBRARY ↔ READING workflow** | βœ… Working | | [persistent_settings_example.py](examples/persistent_settings_example.py) | Settings persistence across sessions | βœ… Working | | [navigation_overlay_example.py](examples/navigation_overlay_example.py) | Unified navigation with tabs | βœ… Working | | [demo_settings_overlay.py](examples/demo_settings_overlay.py) | Settings overlay interactions | βœ… Working | | [word_selection_highlighting.py](examples/word_selection_highlighting.py) | Text highlighting | βœ… Working | **Key Integration Example**: [library_reading_integration.py](examples/library_reading_integration.py) demonstrates the complete user flow: 1. Display library of EPUB files 2. Select book by clicking/tapping 3. Open and read selected book 4. Access settings overlay 5. Return to library from settings 6. Select another book 7. 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**: 1. **Base reading state**: Just the page content 2. **TOC_OVERLAY**: Table of contents over page 3. **SETTINGS_OVERLAY**: Settings panel over page 4. **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: ```python 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. ```json { "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` - **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 1. **Cold Start** (no state file): - Start in LIBRARY mode - Default settings applied 2. **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) 3. **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 mode - `on_library_scroll(direction)` - Scroll library view **READING Mode**: - `on_page_turn(direction)` - Next/Previous page - `on_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 size - `on_word_tap(x, y)` - Single tap on word for quick highlight - `on_word_long_press(x, y)` - Long press on word for lookup overlay **Overlay Mode**: - `on_chapter_selected(chapter_index)` - Jump to chapter - `on_setting_changed(setting_name, value)` - Update settings - `on_bookmark_selected(bookmark_name)` - Jump to bookmark - `on_word_lookup_action(action, word)` - Handle word lookup actions - Actions: dictionary, xray, highlight, copy - `on_xray_occurrence_selected(position)` - Jump to word occurrence - `on_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**: 1. **Bounding Box Approach**: Store bounding boxes for each book element, detect clicks 2. **HTML Links**: Embed book paths as links in HTML, use link query API 3. **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**: 1. **Base64 Embedded**: Encode covers as base64 in HTML (current approach) 2. **File-based**: Save covers to cache directory, reference by path 3. **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**: ```json { "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`) ```python 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`) ```python 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`) ```python 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 brightness - `show_loading(message: str)` - Display loading indicator **From HAL to Application**: - `on_touch(x: int, y: int, gesture: GestureType)` - Touch event - `on_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: 1. **Base Layer**: Main content (library view or reading page) 2. **Overlay Layer**: Semi-transparent overlays (TOC, settings, etc.) 3. **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): 1. βœ… Basic EbookReader class (application.py - complete) 2. βœ… HTML generation for reading view (html_generator.py - complete) 3. βœ… Book scanning and metadata extraction (book_utils.py - complete) 4. βœ… State management module with persistence (state.py - complete) 5. βœ… Library manager with clickable book selection (library.py - complete) 6. βœ… Mode transitions (LIBRARY ↔ READING) - **FULLY DEMONSTRATED** in [examples/library_reading_integration.py](examples/library_reading_integration.py) 7. βœ… Basic overlays (TOC, Settings) - overlay.py + application.py methods complete 8. βœ… Gesture/touch handling (gesture.py - complete with TouchEvent, GestureType, GestureResponse) 9. βœ… Full application integration - **WORKING EXAMPLES EXIST**, needs production main.py controller ### Phase 2: 1. βœ… Bookmarks overlay with management (application.py:1351-1377 - complete) 2. βœ… 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 3. βœ… 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) 4. 🚧 Error handling and user feedback 5. 🚧 Performance optimization 6. πŸ”œ Word lookup overlay (Dictionary + X-Ray feature) - spec complete, not implemented 7. βœ… 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: 1. Advanced library features (search, sort, filter) 2. Advanced highlighting (color picker, annotation notes) 3. Enhanced X-Ray (character relationships, concept maps) 4. Themes and customization 5. Offline dictionary database 6. 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](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 ```python 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 ```python 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 ```python 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 ```python 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:** ```python 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.py` with `DReaderApplication` class - [ ] 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):** ```python # 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:** ```python # 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:** ```python # 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: 1. User can browse library and select a book with a single tap 2. Selected book opens at last read position (or first page if new) 3. User can turn pages forward/backward via tap or swipe 4. User can open TOC and jump to any chapter 5. User can adjust font size and see changes immediately 6. User can add/remove bookmarks and navigate to them 7. Application state persists across reboots 8. Application resumes exactly where user left off after power cycle 9. All features work on target hardware with acceptable performance 10. No data loss on unexpected shutdown/crash