This commit implements true page-based pagination for the ebook reader, similar to Kindle's approach where content is split into discrete pages based on viewport size, font settings, and content layout. Phase 1 - Bug Fixes: - Fix goToPage to use getScrollPositionForPage instead of treating page numbers as spine indices - Move page calculation to initialize before first render to avoid race condition with scroll handler - Add fallback page calculation when pageCalculationResult is null Phase 2 - Page Splitting: - Add new page-splitter.ts module with CFI-based splitting for EPUB and height-based fallback for other formats - Integrate splitContent into page-calculator to generate discrete page content for each spine item - Store pages[] array in ChapterPageInfo for rendering - Rewrite navigation (nextPage, previousPage, renderSpineItem) to use page-based approach with currentPage tracking - Remove old scroll-based pagination from view-modes.ts - Update paginated mode CSS for true page clipping Phase 3 - Progress Display: - Update progress-indicator to use currentPage directly instead of calculating from scroll position - Fix getCurrentPage in reader-state to return currentPage for ebooks Phase 4 - Interface Fixes: - Add currentPage field to UniversalReader interface - Update sendProgressUpdate to use currentPage directly - Initialize currentPage to 1 on reader creation Key features: - Dynamic page count based on font size, line height, margins - CFI-based page splitting preserves reading context - Falls back to height-based splitting for non-EPUB formats - Progress display updates immediately on page change - Settings changes trigger page recalculation and re-render
45 lines
1.1 KiB
TypeScript
45 lines
1.1 KiB
TypeScript
import type { ReaderState } from "./reader-context";
|
|
|
|
type CurrentReader = import("./reader-context").CurrentReader;
|
|
|
|
let currentState: ReaderState = {
|
|
currentReader: null,
|
|
readerMetadata: null,
|
|
};
|
|
|
|
export function getState(): ReaderState {
|
|
return { ...currentState };
|
|
}
|
|
|
|
export function setState(updates: Partial<ReaderState>): void {
|
|
const oldState = { ...currentState };
|
|
currentState = { ...currentState, ...updates };
|
|
|
|
// Emit events for significant changes
|
|
if (
|
|
updates.currentReader &&
|
|
oldState.currentReader !== updates.currentReader
|
|
) {
|
|
readerEvents.emit("readerReady", currentState.currentReader);
|
|
}
|
|
}
|
|
|
|
export function getCurrentReader(): CurrentReader | null {
|
|
return currentState.currentReader;
|
|
}
|
|
|
|
export function getReaderMetadata(): ReaderMetadata | null {
|
|
return currentState.readerMetadata;
|
|
}
|
|
|
|
export function getCurrentPage(): number {
|
|
const reader = currentState.currentReader;
|
|
if (!reader) return 0;
|
|
if (reader.type === "ebook") {
|
|
return reader.currentPage ?? reader.currentSpineIndex + 1;
|
|
}
|
|
return reader.currentPage;
|
|
}
|
|
|
|
import { readerEvents } from "./reader-events";
|