import type { ReaderContext } from "../core/reader-context"; interface ProgressDisplay { mode: "pages" | "chapter" | "percentage" | "time-left"; text: string; } let context: ReaderContext; export async function init(readerContext: ReaderContext): Promise { context = readerContext; context.events.on("pageChanged", () => { updateProgressDisplay(context); }); context.events.on("progressUpdated", () => { updateProgressDisplay(context); }); setupProgressModeCycling(context); } export { calculateProgress, cycleProgressMode }; export type { ProgressDisplay }; function calculateProgress( currentPage: number, totalPages: number, currentChapterPage: number, chapterPages: number, readingSpeed?: ReadingSpeed, ): ProgressDisplay { const mode = getCurrentProgressMode(); switch (mode) { case "pages": return { mode: "pages", text: `${currentPage}/${totalPages}`, }; case "chapter": return { mode: "chapter", text: `${currentChapterPage}/${chapterPages}`, }; case "percentage": const percentage = Math.round((currentPage / totalPages) * 100); return { mode: "percentage", text: `${percentage}%`, }; case "time-left": if (!readingSpeed || readingSpeed.pages_per_minute === 0) { return { mode: "time-left", text: "--:--" }; } const pagesLeft = totalPages - currentPage; const minutesLeft = pagesLeft / readingSpeed.pages_per_minute; const hours = Math.floor(minutesLeft / 60); const mins = Math.round(minutesLeft % 60); return { mode: "time-left", text: `${hours}h ${mins}m`, }; default: return { mode: "pages", text: `${currentPage}/${totalPages}` }; } } function cycleProgressMode(): void { const modes: Array<"pages" | "chapter" | "percentage" | "time-left"> = [ "pages", "chapter", "percentage", "time-left", ]; const currentMode = getCurrentProgressMode(); const currentIndex = modes.indexOf(currentMode); const nextMode = modes[(currentIndex + 1) % modes.length]; setProgressMode(nextMode); } function getCurrentProgressMode(): ReaderSettings["progress_mode"] { const settingsStr = localStorage.getItem("reader_settings_progress_mode"); if (settingsStr) { try { return JSON.parse(settingsStr); } catch { return "pages"; } } return "pages"; } function setProgressMode(mode: ReaderSettings["progress_mode"]): void { localStorage.setItem("reader_settings_progress_mode", JSON.stringify(mode)); const display = document.getElementById("progress-display"); if (display) { display.dataset.mode = mode; } } async function getReadingSpeed(): Promise { const speedStr = localStorage.getItem("reader_speed_data"); if (speedStr) { try { return JSON.parse(speedStr); } catch { return null; } } return null; } function updateProgressDisplay(context: ReaderContext): void { const state = context.getState(); const display = context.elements.progressDisplay; if (!display || !state.currentReader) return; let currentPage = 0; let totalPages = 0; if (state.currentReader.type === "ebook") { currentPage = state.currentReader.currentSpineIndex + 1; totalPages = state.currentReader.cif.spine.length; } else if (state.currentReader.type === "pdf") { currentPage = state.currentReader.currentPage; totalPages = state.readerMetadata?.total_pages || 0; } else { currentPage = state.currentReader.currentPage; totalPages = state.currentReader.images.length; } getReadingSpeed().then((speed) => { const result = calculateProgress( currentPage, totalPages, 0, 0, speed || undefined, ); display.textContent = result.text; display.dataset.mode = result.mode; }); } function setupProgressModeCycling(context: ReaderContext): void { const display = context.elements.progressDisplay; if (!display) return; display.style.cursor = "pointer"; display.addEventListener("click", () => { cycleProgressMode(); updateProgressDisplay(context); }); }