Update v1.0.49 (#330)

* Added PDF top tab strip visibility toggle and fixed WebView hit test NPE

* Refactored desktop reader screens and state management into specialized components

* Added image gallery to reader sidebar and refactored desktop PDF UI components

* Implemented EPUB image gallery

* Refactored reader and library models to use shared common types, centralizing file type resolution and texture management while removing redundant mapping logic

* Standardized UI styling and refactored app navigation layout

* Implemented auto-hiding reader chrome and activity tracking in desktop

* Refactored reader panels into distinct left and right modal layers with platform-specific sizing and keyboard navigation support.

* Added PPTX support for desktop and refactored parsing into a shared module

* Implement paid AI features and account management for the desktop application.

* Implement AI Hub and enhanced Cloud TTS integration for Desktop

* Implement streaming support for AI definition and summarization features

* Implement support for password-protected PDFs and file actions in the desktop reader.

* Implement cloud synchronization for desktop using Firestore and Google Drive

* Implement PDF reflow and "Text View" for the desktop reader

* Refactor OPDS logic to use SharedOpdsController

* Optimize PDF tile rendering performance

* Implement two-page spread support for PDF pagination

* Implement two-page spread support for the PDF viewer

* Improved shared spread zoom in PDF viewer

* Improve PDF spread navigation with fling support and configurable page gaps

* Add brightness control to PDF and EPUB readers

* Refactor folder synchronization to use shared logic engine

* Implement safe string formatting and validation for localized resources

* Implement TTS chunk skip navigation

* Implement deep-linking and playback controls for TTS media sessions

* Implement start index for TTS playback

* Improve TTS navigation, prefetching, and notification duration reporting

* Implement TTS mini playback bar for background reading

* Implement multi-window reader support for the desktop application

* Improve desktop modal window management and visibility syncing

* Implement localized string support for Desktop and shared UI

* Implement language selection and persistence for Desktop

* Implement plural string support for Desktop and migrate hardcoded counts to plurals.xml

* Implement localized banner messages and UI strings using resource-backed SharedText

* Implement compact badge styling for small book covers

* Refactor PDF native interaction and improve HTML import memory safety

* fix language persistence

* Refactor reader overflow menus to use section-based logic

* Refactor PDF layout remapping and improve text box interaction

* Improve CFI resolution and TTS resume accuracy using dynamic chunk offsets

* Centralize PDF annotation export mapping and improve metadata handling

* Add support for threaded comments in PDF highlight annotations

* Flatten highlight comments into a single thread for PDF export and allow author editing

* Integrate page slider into reader chrome and persist toggle state

* Handle fragments and queries in EPUB chapter paths

* Implement dynamic, theme-aware coloring for the reader slider

* Implement customizable app-wide font preference

* Implement one-hand zoom gestures in the PDF viewer

* Implement File Information dialog for PDF and EPUB readers

* Bump version to 1.0.49 (53)

* Refactor PDF reader logic into modular components

* Add ProGuard rules to prevent R8 optimization issues in EPUB reader screens

* Add option to use PDF filenames as display names

* Fix preservation of PDF filename display preference in library projection
This commit is contained in:
Aryan 2026-05-20 22:14:01 +05:30 committed by GitHub
parent dc5196526f
commit 9510293ac3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
245 changed files with 37538 additions and 12460 deletions

View file

@ -0,0 +1,141 @@
package com.aryan.reader.pdf
import androidx.compose.ui.geometry.Offset
import com.aryan.reader.shared.pdf.PdfSpreadLayout
import com.aryan.reader.shared.reader.ReaderSettings
internal fun resolveEraserStrokeWidth(
isEraserOverride: Boolean,
activeToolThickness: Float,
eraserToolThickness: Float
): Float = if (isEraserOverride) eraserToolThickness else activeToolThickness
internal fun canUsePdfSidecarsForBook(
activeBookId: String?,
loadedSidecarBookId: String?,
areSidecarsLoaded: Boolean
): Boolean = activeBookId != null && areSidecarsLoaded && loadedSidecarBookId == activeBookId
internal fun canManagePdfVirtualPages(
isDocumentReady: Boolean,
currentBookId: String?,
loadedPageLayoutBookId: String?,
virtualPageCount: Int
): Boolean {
return isDocumentReady &&
currentBookId != null &&
loadedPageLayoutBookId == currentBookId &&
virtualPageCount > 0
}
internal fun currentPageScaleAfterPdfPageChange(
displayMode: DisplayMode,
isScrollLocked: Boolean,
lockedState: Triple<Float, Float, Float>?,
currentActiveScale: Float
): Float {
return if (displayMode == DisplayMode.PAGINATION && isScrollLocked) {
lockedState?.first ?: currentActiveScale
} else {
1f
}
}
internal fun pdfPageRangeText(
pageIndex: Int,
pageCount: Int,
displayMode: DisplayMode,
settings: ReaderSettings
): String {
val pageRange = if (displayMode == DisplayMode.PAGINATION) {
PdfSpreadLayout.pageRangeLabel(pageIndex, pageCount, settings)
} else {
"${pageIndex.coerceIn(0, (pageCount - 1).coerceAtLeast(0)) + 1}"
}
return "$pageRange / $pageCount"
}
internal fun pdfPageRangeLabel(
pageIndex: Int,
pageCount: Int,
displayMode: DisplayMode,
settings: ReaderSettings
): String {
val pageRange = if (displayMode == DisplayMode.PAGINATION) {
PdfSpreadLayout.pageRangeLabel(pageIndex, pageCount, settings)
} else {
"${pageIndex.coerceIn(0, (pageCount - 1).coerceAtLeast(0)) + 1}"
}
return if ('-' in pageRange) {
"Pages $pageRange of $pageCount"
} else {
"Page $pageRange of $pageCount"
}
}
internal fun clampPdfSpreadCameraOffset(
scale: Float,
offset: Offset,
viewportWidth: Float,
viewportHeight: Float
): Offset {
if (viewportWidth <= 0f || viewportHeight <= 0f || scale <= 1f) return Offset.Zero
val maxOffsetX = ((viewportWidth * scale) - viewportWidth).coerceAtLeast(0f) / 2f
val maxOffsetY = ((viewportHeight * scale) - viewportHeight).coerceAtLeast(0f) / 2f
return Offset(
x = offset.x.coerceIn(-maxOffsetX, maxOffsetX),
y = offset.y.coerceIn(-maxOffsetY, maxOffsetY)
)
}
internal fun activePdfCameraAfterLockPreferenceLoad(
isScrollLocked: Boolean,
lockedState: Triple<Float, Float, Float>?
): Pair<Float, Offset> {
return if (isScrollLocked && lockedState != null) {
lockedState.first to Offset(lockedState.second, lockedState.third)
} else {
1f to Offset.Zero
}
}
internal fun shouldReportPdfPageCamera(
isZoomEnabled: Boolean,
isVerticalScroll: Boolean,
isScrollLocked: Boolean,
lockedState: Triple<Float, Float, Float>?,
hasAppliedLockedState: Boolean
): Boolean {
return !isZoomEnabled ||
isVerticalScroll ||
!isScrollLocked ||
lockedState == null ||
hasAppliedLockedState
}
internal fun initialPdfPageCamera(
isZoomEnabled: Boolean,
isVerticalScroll: Boolean,
isScrollLocked: Boolean,
lockedState: Triple<Float, Float, Float>?
): Pair<Float, Offset> {
return if (isZoomEnabled && !isVerticalScroll && isScrollLocked && lockedState != null) {
lockedState.first to Offset(lockedState.second, lockedState.third)
} else {
1f to Offset.Zero
}
}
internal fun shouldResetPdfZoomAfterBubbleZoomCleanup(
isBubbleZoomModeActive: Boolean,
scale: Float,
isVerticalScroll: Boolean,
isZoomEnabled: Boolean,
isScrollLocked: Boolean
): Boolean {
return !isBubbleZoomModeActive &&
scale > 1f &&
!isVerticalScroll &&
isZoomEnabled &&
!isScrollLocked
}