BREAKING CHANGE: Unify ebook reader type system to match actual data structures Problem: - ReflowableBook type had direct properties (spine, resources, toc, metadata) - UniversalReader wraps EbookCIF in cif property with runtime state - Type mismatch caused unsafe 'as any' casts and runtime errors - Two conflicting UniversalReader definitions existed (reader-shell vs reader-context) Root Cause: - Parsers return EbookCIF (nested structure) - ReflowableBook expected flat structure - Code mixed both approaches causing confusion Changes: Type System Updates: - Replace all ReflowableBook references with UniversalReader - Remove duplicate UniversalReader definition in reader-context.ts - Import UniversalReader from canonical source (reader-shell.ts) - Update all function signatures across reflowable module Property Access Patterns: - book.cif.spine instead of book.spine - book.cif.resources instead of book.resources - book.cif.toc instead of book.toc - book.cif.metadata instead of book.metadata Fixed Modules: - reader-shell.ts: UniversalReader object construction - reader-context.ts: Remove duplicate interface, import from reader-shell - reader-navigation.ts: Remove unsafe type casts, fix property access - reader-services.ts: Align with UniversalReader structure - reflowable/navigation.ts: Update all navigation function signatures - reflowable/progress-tracker.ts: Update tracker function signatures - reflowable/parser.ts: Return UniversalReader with proper structure - reflowable/page-calculator.ts: Update calculation function signatures - reflowable/ebook/search.ts: Fix property access patterns - types/reader.d.ts: Remove duplicate type definitions Impact: - ✅ Type-safe throughout ebook reader - ✅ Matches actual data structures from parsers - ✅ No more unsafe type casts - ✅ Single source of truth for UniversalReader - ✅ Aligns with EbookCIF format from API/parsers Files changed: 10 Lines changed: +320, -180
84 lines
2.0 KiB
TypeScript
84 lines
2.0 KiB
TypeScript
// Import types
|
|
import type { ReadingPosition } from "./types";
|
|
import { findPageByCFI, createPositionFromPage } from "./page-calculator";
|
|
import { UniversalReader } from "../../reader-shell";
|
|
|
|
// Update current position
|
|
export function updateCurrentPosition(
|
|
book: UniversalReader,
|
|
position: ReadingPosition,
|
|
): UniversalReader {
|
|
return {
|
|
...book,
|
|
position,
|
|
};
|
|
}
|
|
|
|
// Extract CFI from position
|
|
export function getCurrentCFI(book: UniversalReader): string {
|
|
return book.position.cfi;
|
|
}
|
|
|
|
// Calculate progress for display
|
|
export function calculateProgress(book: UniversalReader): {
|
|
currentPage: number;
|
|
totalPages: number;
|
|
percentage: number;
|
|
} {
|
|
const totalPages = book.pagination?.totalPages || 1;
|
|
const currentPage = book.position.currentPage;
|
|
const percentage =
|
|
totalPages > 0 ? Math.round((currentPage / totalPages) * 100) : 0;
|
|
|
|
return { currentPage, totalPages, percentage };
|
|
}
|
|
|
|
// Get position for saving to database
|
|
export function getPositionForSave(book: UniversalReader): {
|
|
cfi: string;
|
|
progress: number;
|
|
page: number;
|
|
} {
|
|
return {
|
|
cfi: book.position.cfi,
|
|
progress: book.position.progress,
|
|
page: book.position.currentPage,
|
|
};
|
|
}
|
|
|
|
// Restore position from database
|
|
export function restorePosition(
|
|
book: UniversalReader,
|
|
savedCFI: string,
|
|
savedPage?: number,
|
|
): ReadingPosition {
|
|
if (!book.pagination) {
|
|
return book.position;
|
|
}
|
|
|
|
// If we have saved CFI, try to find exact position
|
|
if (savedCFI) {
|
|
const pageNum = findPageByCFI(book.pagination, savedCFI);
|
|
return createPositionFromPage(book, pageNum);
|
|
}
|
|
|
|
// Otherwise use saved page number
|
|
if (savedPage && savedPage > 0) {
|
|
return createPositionFromPage(book, savedPage);
|
|
}
|
|
|
|
return book.position;
|
|
}
|
|
|
|
// Check if position changed significantly
|
|
export function didPositionChange(
|
|
oldPos: ReadingPosition,
|
|
newPos: ReadingPosition,
|
|
): boolean {
|
|
return (
|
|
oldPos.currentPage !== newPos.currentPage ||
|
|
oldPos.cfi !== newPos.cfi ||
|
|
Math.abs(oldPos.progress - newPos.progress) > 0.01
|
|
);
|
|
}
|