General fixes (#76)
* Added print functionality to PDF viewer * feat(pdf): add interactive button support and visibility reveal heuristic * Moved search state management to MainViewModel and improved search UI interaction. * Updated `pdfiumandroid` to version 2.0.0 and handled resulting API changes, including nullable page/text page returns and revised native pointer access. increased compileSdk to 36. * Fixed Table of Contents (TOC) truncation bug and improved the TOC UI in `PdfViewerScreen`. - Implemented `getFixedTableOfContents` using reflection to bypass a library issue where sibling nodes were incorrectly truncated during traversal. - Enhanced the TOC drawer with a nested, expandable tree structure using the new `PdfTocTreeItem` component. - Added a custom `VerticalScrollbar` with draggable support for better navigation within long TOC lists. - Integrated `animateColorAsState` and `animateFloatAsState` for smoother UI transitions in the TOC and scrollbar. - Optimized TOC loading by flattening the tree structure and managing expansion states with `rememberSaveable`. * Improved zoom pivot calculation and interaction handling in PdfVerticalReader * Fixed high-res PDF tile bleeding by implementing clipRect in PdfBitmapLayer * fix(pdf): resolve zoom stuttering, in pagination mode, by removing eager scale snapping
This commit is contained in:
parent
dece09fec0
commit
1884ace646
12 changed files with 1207 additions and 653 deletions
|
|
@ -358,8 +358,12 @@ internal fun PdfVerticalReader(
|
|||
val constrainedX = targetPanX.coerceIn(minPanX, maxPanX)
|
||||
val constrainedY = targetPanY.coerceIn(minPanY, headerHeightPx)
|
||||
|
||||
// DEDICATED LOG
|
||||
Timber.tag("PdfZoomDebug").v("Clamp Internal: Zoom=$constrainedZoom, PanBoundsX=[$minPanX, $maxPanX], PanBoundsY=[$minPanY, $headerHeightPx]")
|
||||
if (constrainedZoom > 1.01f) {
|
||||
Timber.tag("PdfZoomIssue").v(
|
||||
"Clamp: Zoom=$constrainedZoom, targetY=$targetPanY, finalY=$constrainedY, " +
|
||||
"boundsY=[$minPanY, $headerHeightPx], zoomedHeight=$zoomedDocHeight"
|
||||
)
|
||||
}
|
||||
|
||||
return Triple(constrainedZoom, constrainedX, constrainedY)
|
||||
}
|
||||
|
|
@ -370,10 +374,14 @@ internal fun PdfVerticalReader(
|
|||
return clampValues(targetZoom, targetPanX, targetPanY)
|
||||
}
|
||||
|
||||
var isFlinging by remember { mutableStateOf(false) }
|
||||
var isFastFlinging by remember { mutableStateOf(false) }
|
||||
var isInteracting by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(
|
||||
totalDocHeight, screenHeight, headerHeightPx, footerHeightPx, zoomAnimatable.value
|
||||
totalDocHeight, screenHeight, headerHeightPx, footerHeightPx, zoomAnimatable.value, isInteracting, isFlinging
|
||||
) {
|
||||
if (zoomAnimatable.isRunning || panXAnimatable.isRunning || panYAnimatable.isRunning) {
|
||||
if (zoomAnimatable.isRunning || panXAnimatable.isRunning || panYAnimatable.isRunning || isInteracting || isFlinging) {
|
||||
return@LaunchedEffect
|
||||
}
|
||||
|
||||
|
|
@ -446,10 +454,6 @@ internal fun PdfVerticalReader(
|
|||
}
|
||||
|
||||
var selectionClearTrigger by remember { mutableLongStateOf(0L) }
|
||||
|
||||
var isFlinging by remember { mutableStateOf(false) }
|
||||
var isFastFlinging by remember { mutableStateOf(false) }
|
||||
|
||||
var draggingBoxId by remember { mutableStateOf<String?>(null) }
|
||||
var draggingBoxOffset by remember { mutableStateOf(Offset.Zero) }
|
||||
var draggingBoxSize by remember { mutableStateOf(Size.Zero) }
|
||||
|
|
@ -549,7 +553,6 @@ internal fun PdfVerticalReader(
|
|||
}
|
||||
|
||||
var highResScale by remember { mutableFloatStateOf(1f) }
|
||||
var isInteracting by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(isInteracting) {
|
||||
if (isInteracting && isAutoScrollPlaying) {
|
||||
|
|
@ -617,8 +620,12 @@ internal fun PdfVerticalReader(
|
|||
imeBottom,
|
||||
isEditMode,
|
||||
selectedTool,
|
||||
zoomAnimatable.value
|
||||
zoomAnimatable.value,
|
||||
isInteracting,
|
||||
isFlinging
|
||||
) {
|
||||
if (isInteracting || isFlinging) return@LaunchedEffect
|
||||
|
||||
val currentZoom = zoomAnimatable.value
|
||||
val zoomedDocHeight = totalDocHeight * currentZoom
|
||||
|
||||
|
|
@ -897,6 +904,7 @@ internal fun PdfVerticalReader(
|
|||
)
|
||||
|
||||
val down = awaitFirstDown(requireUnconsumed = false)
|
||||
isInteracting = true
|
||||
|
||||
Timber.tag("PointerTypeDebug").d("VerticalReader: Input Type detected: ${down.type}")
|
||||
|
||||
|
|
@ -1015,31 +1023,35 @@ internal fun PdfVerticalReader(
|
|||
(!isEditMode || selectedTool == InkType.TEXT || isMultiTouch || (isStylusOnlyMode && isTouchInput))
|
||||
|
||||
if (shouldScroll) {
|
||||
if (!isInteracting) {
|
||||
Timber.tag("PdfTouchDebug").i(
|
||||
"VerticalReader: Taking control."
|
||||
)
|
||||
isInteracting = true
|
||||
}
|
||||
|
||||
panLocked = true
|
||||
if (zoomChange != 1f || panChange != Offset.Zero) {
|
||||
|
||||
var effectiveZoomChange = zoomChange
|
||||
|
||||
if (gestureDisambiguationMode == 1) {
|
||||
effectiveZoomChange = 1f
|
||||
}
|
||||
if (gestureDisambiguationMode == 1) effectiveZoomChange = 1f
|
||||
|
||||
val oldZoom = accumulatedZoom
|
||||
val rawTargetZoom = oldZoom * effectiveZoomChange
|
||||
val constrainedZoom = rawTargetZoom.coerceIn(1f, 5f)
|
||||
val actualZoomFactor = if (oldZoom == 0f) 1f
|
||||
else constrainedZoom / oldZoom
|
||||
val rawNewPanX =
|
||||
(accumulatedPanX + panChange.x) - (centroid.x - accumulatedPanX) * (actualZoomFactor - 1)
|
||||
val rawNewPanY =
|
||||
(accumulatedPanY + panChange.y) - (centroid.y - accumulatedPanY) * (actualZoomFactor - 1)
|
||||
|
||||
val prevCentroid = centroid - panChange
|
||||
val contentPivotX = (prevCentroid.x - accumulatedPanX) / oldZoom
|
||||
val contentPivotY = (prevCentroid.y - accumulatedPanY) / oldZoom
|
||||
|
||||
Timber.tag("PdfZoomIssue").v(
|
||||
"PivotCalc: ScreenCentroidY=${centroid.y}, DocumentPanY=$accumulatedPanY, " +
|
||||
"CalculatedContentPivotY=$contentPivotY"
|
||||
)
|
||||
|
||||
val rawNewPanX = centroid.x - (contentPivotX * constrainedZoom)
|
||||
val rawNewPanY = centroid.y - (contentPivotY * constrainedZoom)
|
||||
|
||||
if (effectiveZoomChange > 1.0f) {
|
||||
Timber.tag("PdfZoomIssue").d(
|
||||
"PinchIn FIXED: ZoomFactor=$effectiveZoomChange, CentroidY=${centroid.y}, " +
|
||||
"OldPanY=$accumulatedPanY, ResultRawPanY=$rawNewPanY"
|
||||
)
|
||||
}
|
||||
|
||||
val (finalZoom, finalX, finalY) = clampCamera(
|
||||
constrainedZoom, rawNewPanX, rawNewPanY
|
||||
)
|
||||
|
|
@ -1064,11 +1076,8 @@ internal fun PdfVerticalReader(
|
|||
|
||||
if (event.changes.isNotEmpty()) {
|
||||
velocityTrackerAccumulator += panChange
|
||||
|
||||
val time = event.changes[0].uptimeMillis
|
||||
tracker.addPosition(
|
||||
time, velocityTrackerAccumulator
|
||||
)
|
||||
tracker.addPosition(time, velocityTrackerAccumulator)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue