dreader-application/REQUIREMENTS.md
Duncan Tourolle 01e79dfa4b
All checks were successful
Python CI / test (3.12) (push) Successful in 22m19s
Python CI / test (3.13) (push) Successful in 8m23s
Test appplication for offdevice testing
2025-11-09 17:47:34 +01:00

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:

  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:

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
  • 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:

{
  "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 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
  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 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.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):

# 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:

  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