#!/usr/bin/env python3 """ Integration demo: Library → Reading → Settings → Back to Library This example demonstrates the complete LIBRARY ↔ READING mode transition workflow: 1. Display a library of EPUB files 2. Select a book by clicking/tapping 3. Open and read the selected book 4. Access settings overlay 5. Return to library from the settings overlay 6. Select another book This demonstrates the full user flow for an e-reader application. Usage: python library_reading_integration.py path/to/library/directory """ import sys import os from pathlib import Path # Add parent directory to path to import dreader sys.path.insert(0, str(Path(__file__).parent.parent)) from dreader.library import LibraryManager from dreader.application import EbookReader from dreader.gesture import TouchEvent, GestureType, ActionType def print_separator(): """Print a visual separator.""" print("\n" + "="*70 + "\n") def simulate_mode_transition_workflow(library_path: str): """ Simulate the complete workflow of library browsing and book reading. Args: library_path: Path to directory containing EPUB files """ print_separator() print("INTEGRATION TEST: LIBRARY ↔ READING MODE TRANSITIONS") print_separator() # =================================================================== # STEP 1: LIBRARY MODE - Display available books # =================================================================== print("STEP 1: LIBRARY MODE - Displaying available books") print("-" * 70) # Initialize library manager library = LibraryManager( library_path=library_path, page_size=(800, 1200) ) # Scan for books books = library.scan_library() print(f"✓ Found {len(books)} books in library") if len(books) == 0: print("Error: No EPUB files found in library directory") print(f"Please add some .epub files to: {library_path}") sys.exit(1) # Display book list for i, book in enumerate(books): print(f" [{i}] {book['title']} by {book['author']}") # Render library view print("\nRendering library view...") library_image = library.render_library() library_image.save("integration_01_library.png") print("✓ Saved library view to: integration_01_library.png") # =================================================================== # STEP 2: SIMULATE BOOK SELECTION - User taps on first book # =================================================================== print_separator() print("STEP 2: BOOK SELECTION - Simulating tap on first book") print("-" * 70) # Simulate a tap on the first book row # Row positions depend on rendering, but first book is typically near top # We'll tap in the middle of the first book row area tap_x, tap_y = 400, 150 # Approximate center of first book row print(f"Simulating tap at ({tap_x}, {tap_y})...") selected_book_path = library.handle_library_tap(tap_x, tap_y) if not selected_book_path: print("Warning: Tap didn't hit a book. Selecting first book directly...") selected_book_path = books[0]['path'] print(f"✓ Selected book: {selected_book_path}") # =================================================================== # STEP 3: READING MODE - Open the selected book # =================================================================== print_separator() print("STEP 3: READING MODE - Opening selected book") print("-" * 70) # Create reader reader = EbookReader( page_size=(800, 1200), margin=40, background_color=(255, 255, 255) ) # Load the EPUB print(f"Loading: {selected_book_path}") success = reader.load_epub(selected_book_path) if not success: print("Error: Failed to load EPUB") sys.exit(1) print("✓ Book loaded successfully") # Get book info book_info = reader.get_book_info() print(f" Title: {book_info['title']}") print(f" Author: {book_info['author']}") print(f" Chapters: {book_info['total_chapters']}") # Render first page print("\nRendering first page...") page_image = reader.get_current_page() page_image.save("integration_02_reading_page1.png") print("✓ Saved first page to: integration_02_reading_page1.png") # =================================================================== # STEP 4: PAGE NAVIGATION - Turn some pages # =================================================================== print_separator() print("STEP 4: PAGE NAVIGATION - Simulating page turns") print("-" * 70) # Simulate swipe left (next page) print("Simulating SWIPE_LEFT (next page)...") touch_event = TouchEvent(GestureType.SWIPE_LEFT, 600, 600) response = reader.handle_touch(touch_event) if response.action == ActionType.PAGE_TURN: print(f"✓ Page turned: {response.data}") page_image = reader.get_current_page() page_image.save("integration_03_reading_page2.png") print(" Saved to: integration_03_reading_page2.png") # Turn another page print("\nSimulating another SWIPE_LEFT...") touch_event = TouchEvent(GestureType.SWIPE_LEFT, 600, 600) response = reader.handle_touch(touch_event) if response.action == ActionType.PAGE_TURN: print(f"✓ Page turned: {response.data}") # =================================================================== # STEP 5: SETTINGS OVERLAY - Open and adjust settings # =================================================================== print_separator() print("STEP 5: SETTINGS OVERLAY - Opening settings") print("-" * 70) # Open settings overlay print("Opening settings overlay...") overlay_image = reader.open_settings_overlay() if overlay_image: overlay_image.save("integration_04_settings_overlay.png") print("✓ Settings overlay opened") print(" Saved to: integration_04_settings_overlay.png") # Simulate tapping "Increase Font Size" button print("\nSimulating tap on 'Increase Font Size'...") # The increase button is typically around y=250-280 in the overlay tap_x, tap_y = 400, 270 touch_event = TouchEvent(GestureType.TAP, tap_x, tap_y) response = reader.handle_touch(touch_event) if response.action == ActionType.SETTING_CHANGED: print(f"✓ Setting changed: {response.data}") updated_overlay = reader.get_current_page() updated_overlay.save("integration_05_settings_font_increased.png") print(" Saved updated overlay to: integration_05_settings_font_increased.png") # =================================================================== # STEP 6: BACK TO LIBRARY - Use the new "Back to Library" button # =================================================================== print_separator() print("STEP 6: BACK TO LIBRARY - Using 'Back to Library' button") print("-" * 70) # The settings overlay is 60% width x 70% height, centered # For 800x1200: panel is 480x840, offset at (160, 180) # The "Back to Library" button is near the bottom of the overlay panel # Let's try scanning for it by querying multiple y-positions print("Scanning for 'Back to Library' button...") found_button = False # Scan a wider range with finer granularity # Settings overlay is 60% x 70% of 800x1200 = 480x840, centered at (160, 180) # So overlay goes from y=180 to y=1020 # Button should be near bottom, scan from y=600 to y=1020 debug_results = [] for test_y in range(600, 1021, 20): test_x = 400 # Center of screen # Use the overlay manager's query method if there's an overlay open if hasattr(reader, 'overlay_manager'): result = reader.overlay_manager.query_overlay_pixel(test_x, test_y) if result: debug_results.append((test_y, result.get("link_target"), result.get("text", "")[:30])) if result.get("is_interactive") and result.get("link_target"): link = result["link_target"] if link == "action:back_to_library": print(f"✓ Found button at approximately ({test_x}, {test_y})") tap_x, tap_y = test_x, test_y found_button = True break if not found_button and debug_results: print(f" Debug: Scanned {len(debug_results)} positions, found these links:") for y, link, text in debug_results[-5:]: # Show last 5 if link: print(f" y={y}: link={link}, text='{text}'") if not found_button: print(" Button not found via scan, using estimated position...") # Fallback: overlay height is 840, centered at y=180 # Button is near bottom, approximately at panel_y + panel_height - 100 tap_x, tap_y = 400, 900 print(f"Simulating tap at ({tap_x}, {tap_y})...") touch_event = TouchEvent(GestureType.TAP, tap_x, tap_y) response = reader.handle_touch(touch_event) if response.action == ActionType.BACK_TO_LIBRARY: print("✓ BACK_TO_LIBRARY action received!") print(" Application would now:") print(" 1. Close the current book") print(" 2. Return to library view") print(" 3. Save reading position for resume") # Save current position for resume reader.save_position("__auto_resume__") print("\n ✓ Auto-resume position saved") # Close the reader reader.close() print(" ✓ Book closed") # Re-render library print("\n Re-rendering library view...") library_image = library.render_library() library_image.save("integration_06_back_to_library.png") print(" ✓ Saved library view to: integration_06_back_to_library.png") else: print(f"Unexpected response: {response.action}") print("Note: The button might be outside the overlay area or coordinates need adjustment") # =================================================================== # STEP 7: SELECT ANOTHER BOOK (if multiple books available) # =================================================================== if len(books) > 1: print_separator() print("STEP 7: SELECTING ANOTHER BOOK") print("-" * 70) # Select second book second_book_path = books[1]['path'] print(f"Selecting second book: {second_book_path}") # Create new reader instance reader2 = EbookReader( page_size=(800, 1200), margin=40, background_color=(255, 255, 255) ) # Load second book success = reader2.load_epub(second_book_path) if success: book_info = reader2.get_book_info() print(f"✓ Loaded: {book_info['title']} by {book_info['author']}") # Render first page page_image = reader2.get_current_page() page_image.save("integration_07_second_book.png") print(" Saved to: integration_07_second_book.png") reader2.close() # =================================================================== # STEP 8: RESUME PREVIOUS BOOK (demonstrate auto-resume) # =================================================================== print_separator() print("STEP 8: AUTO-RESUME - Reopening first book at saved position") print("-" * 70) # Create new reader reader3 = EbookReader( page_size=(800, 1200), margin=40, background_color=(255, 255, 255) ) # Load the book print(f"Reloading: {selected_book_path}") success = reader3.load_epub(selected_book_path) if success: # Load auto-resume position print("Loading auto-resume position...") page = reader3.load_position("__auto_resume__") if page: print("✓ Resumed at saved position!") pos_info = reader3.get_position_info() print(f" Progress: {pos_info['progress']*100:.1f}%") page.save("integration_08_resumed_position.png") print(" Saved to: integration_08_resumed_position.png") else: print("No saved position found (started from beginning)") reader3.close() # Cleanup library.cleanup() print_separator() print("✓ INTEGRATION TEST COMPLETE!") print_separator() print("\nGenerated demonstration images:") demo_files = [ "integration_01_library.png", "integration_02_reading_page1.png", "integration_03_reading_page2.png", "integration_04_settings_overlay.png", "integration_05_settings_font_increased.png", "integration_06_back_to_library.png", "integration_07_second_book.png", "integration_08_resumed_position.png" ] for filename in demo_files: if os.path.exists(filename): print(f" ✓ {filename}") print("\nThis demonstrates the complete workflow:") print(" 1. Library view with book selection") print(" 2. Opening and reading a book") print(" 3. Page navigation") print(" 4. Settings overlay with adjustments") print(" 5. Back to library transition") print(" 6. Selecting another book") print(" 7. Auto-resume functionality") def main(): """Main entry point.""" if len(sys.argv) < 2: print("Usage: python library_reading_integration.py path/to/library/directory") print("\nThis demo requires a directory containing EPUB files.") print("\nExample:") print(" mkdir my_library") print(" cp tests/data/test.epub my_library/") print(" cp tests/data/test2.epub my_library/") print(" python library_reading_integration.py my_library/") sys.exit(1) library_path = sys.argv[1] if not os.path.exists(library_path): print(f"Error: Directory not found: {library_path}") sys.exit(1) if not os.path.isdir(library_path): print(f"Error: Not a directory: {library_path}") sys.exit(1) try: simulate_mode_transition_workflow(library_path) except Exception as e: print(f"\nError during integration test: {e}") import traceback traceback.print_exc() sys.exit(1) if __name__ == "__main__": main()