@june24/expo-pdf-reader 0.1.28 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -145,11 +145,17 @@ class ExpoPdfReaderView(
145
145
  }
146
146
 
147
147
  /**
148
- * continuous / twoup / twoupcontinuous — pinch-ийг [dispatchTouchEvent]-ийн эхэнд дуудаж
149
- * 2 хурууны POINTER_DOWN canvas-д баригдахаас өмнө хүлээнэ. Zoom хийсэн ч босоо scroll хэвээр (зөвхөн pinch үед scroll intercept унтрана).
148
+ * continuous / twoup / twoupcontinuous — pinch + zoom хийсэн үед pan (хөндлөн/босоо),
149
+ * scroll-ийг идэвхгүй болгоно. Zoom = 1 үед хэвийн босоо scroll.
150
150
  */
151
151
  private inner class ZoomableScrollView(ctx: Context) : ScrollView(ctx) {
152
152
 
153
+ private var panX = 0f
154
+ private var panY = 0f
155
+
156
+ private fun isZoomedForPan(): Boolean =
157
+ activeTool == null && currentZoom > 1.02f
158
+
153
159
  private val pinch = ScaleGestureDetector(
154
160
  ctx,
155
161
  object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
@@ -181,6 +187,9 @@ class ExpoPdfReaderView(
181
187
  override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
182
188
  if (activeTool != null) return super.onInterceptTouchEvent(ev)
183
189
  if (ev.pointerCount > 1 || pinch.isInProgress) return false
190
+ if (isZoomedForPan() && ev.actionMasked == MotionEvent.ACTION_DOWN) {
191
+ return true
192
+ }
184
193
  return super.onInterceptTouchEvent(ev)
185
194
  }
186
195
 
@@ -205,11 +214,42 @@ class ExpoPdfReaderView(
205
214
 
206
215
  override fun onTouchEvent(ev: MotionEvent): Boolean {
207
216
  if (activeTool != null) return super.onTouchEvent(ev)
217
+
208
218
  if (pinch.isInProgress || ev.pointerCount > 1) {
209
219
  return true
210
220
  }
221
+
222
+ if (isZoomedForPan()) {
223
+ when (ev.actionMasked) {
224
+ MotionEvent.ACTION_DOWN -> {
225
+ stopNestedScroll()
226
+ panX = ev.x
227
+ panY = ev.y
228
+ }
229
+ MotionEvent.ACTION_MOVE -> {
230
+ container.translationX += ev.x - panX
231
+ container.translationY += ev.y - panY
232
+ panX = ev.x
233
+ panY = ev.y
234
+ clampContainerTranslationsInPlace()
235
+ }
236
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { }
237
+ }
238
+ return true
239
+ }
240
+
211
241
  return super.onTouchEvent(ev)
212
242
  }
243
+
244
+ override fun canScrollVertically(direction: Int): Boolean {
245
+ if (isZoomedForPan()) return false
246
+ return super.canScrollVertically(direction)
247
+ }
248
+
249
+ override fun canScrollHorizontally(direction: Int): Boolean {
250
+ if (isZoomedForPan()) return false
251
+ return super.canScrollHorizontally(direction)
252
+ }
213
253
  }
214
254
 
215
255
  // ── UI ───────────────────────────────────────────────────────────────────
@@ -287,6 +327,7 @@ class ExpoPdfReaderView(
287
327
  private fun reflowForHostWidthChange() {
288
328
  val w = width.takeIf { it > 0 } ?: return
289
329
  if (renderer == null) return
330
+ if (w <= 0) return
290
331
  if (lastHostWidthForPdf > 0 && kotlin.math.abs(w - lastHostWidthForPdf) <= 4) return
291
332
  lastHostWidthForPdf = w
292
333
  currentViewWidth = w
@@ -923,7 +964,7 @@ class ExpoPdfReaderView(
923
964
  private suspend fun renderTwoUpRange(
924
965
  pdf: PdfRenderer, pageCount: Int, viewWidth: Int, startPage: Int, endPage: Int
925
966
  ) {
926
- val halfWidth = viewWidth / 2
967
+ val halfWidth = (viewWidth / 2).coerceAtLeast(1)
927
968
  var i = startPage
928
969
  while (i < endPage) {
929
970
  val leftBmp = renderPageBitmap(pdf, i, halfWidth)
@@ -987,12 +1028,21 @@ class ExpoPdfReaderView(
987
1028
  }
988
1029
  }
989
1030
 
1031
+ private fun resolveViewWidthForRender(): Int {
1032
+ val w = when {
1033
+ currentViewWidth > 0 -> currentViewWidth
1034
+ width > 0 -> width
1035
+ else -> resources.displayMetrics.widthPixels
1036
+ }
1037
+ return w.coerceAtLeast(1)
1038
+ }
1039
+
990
1040
  private suspend fun loadNextChunk() {
991
1041
  val pdf = renderer ?: return
992
1042
  val start = renderedUpTo + 1
993
1043
  if (start >= totalPages) return
994
1044
  val end = minOf(start + PAGE_CHUNK, totalPages)
995
- val viewWidth = currentViewWidth
1045
+ val viewWidth = resolveViewWidthForRender()
996
1046
 
997
1047
  withContext(Dispatchers.Main) { removeLoadingFooter() }
998
1048
 
@@ -1055,7 +1105,7 @@ class ExpoPdfReaderView(
1055
1105
  val prevStart = maxOf(0, windowStart - PAGE_CHUNK)
1056
1106
  val prevEnd = windowStart
1057
1107
  if (prevStart >= prevEnd) return
1058
- val viewWidth = currentViewWidth
1108
+ val viewWidth = resolveViewWidthForRender()
1059
1109
 
1060
1110
  data class PageBmp(val bmp: Bitmap, val idx: Int, val pdfW: Float, val pdfH: Float)
1061
1111
  val pages = mutableListOf<PageBmp>()
@@ -1092,8 +1142,8 @@ class ExpoPdfReaderView(
1092
1142
  val prevStart = maxOf(0, windowStart - PAGE_CHUNK)
1093
1143
  val prevEnd = windowStart
1094
1144
  if (prevStart >= prevEnd) return
1095
- val viewWidth = currentViewWidth
1096
- val halfW = viewWidth / 2
1145
+ val viewWidth = resolveViewWidthForRender()
1146
+ val halfW = (viewWidth / 2).coerceAtLeast(1)
1097
1147
 
1098
1148
  data class RowBmps(val leftIdx: Int, val leftBmp: Bitmap, val rightBmp: Bitmap?)
1099
1149
  val rows = mutableListOf<RowBmps>()
@@ -1229,7 +1279,7 @@ class ExpoPdfReaderView(
1229
1279
  */
1230
1280
  private fun jumpToPage(targetPage: Int) {
1231
1281
  val pdf = renderer ?: return
1232
- val viewWidth = currentViewWidth.takeIf { it > 0 } ?: width.takeIf { it > 0 } ?: return
1282
+ val viewWidth = resolveViewWidthForRender()
1233
1283
  renderJob?.cancel()
1234
1284
  renderJob = scope.launch {
1235
1285
  try {
@@ -1348,14 +1398,15 @@ class ExpoPdfReaderView(
1348
1398
 
1349
1399
  private suspend fun renderPageBitmap(pdf: PdfRenderer, index: Int, targetWidth: Int): Bitmap =
1350
1400
  withContext(pdfDispatcher) {
1401
+ val safeWidth = targetWidth.coerceAtLeast(1)
1351
1402
  pdf.openPage(index).use { page ->
1352
1403
  if (index < pagePdfW.size) {
1353
1404
  pagePdfW[index] = page.width
1354
1405
  pagePdfH[index] = page.height
1355
1406
  }
1356
- val s = targetWidth.toFloat() / page.width.toFloat()
1407
+ val s = safeWidth.toFloat() / page.width.toFloat()
1357
1408
  val h = (page.height * s).toInt().coerceAtLeast(1)
1358
- val bmp = Bitmap.createBitmap(targetWidth, h, Bitmap.Config.ARGB_8888)
1409
+ val bmp = Bitmap.createBitmap(safeWidth, h, Bitmap.Config.ARGB_8888)
1359
1410
  bmp.eraseColor(Color.WHITE)
1360
1411
  page.render(bmp, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
1361
1412
  bmp
@@ -1446,7 +1497,18 @@ class ExpoPdfReaderView(
1446
1497
 
1447
1498
  holder.loadJob = scope.launch {
1448
1499
  val pdf = renderer ?: return@launch
1449
- val bmp = renderPageBitmap(pdf, position, this@ExpoPdfReaderView.width)
1500
+ val viewWidth = this@ExpoPdfReaderView.width
1501
+ if (viewWidth <= 0) {
1502
+ withContext(Dispatchers.Main) {
1503
+ post {
1504
+ if (holder.boundPage == position && this@ExpoPdfReaderView.width > 0) {
1505
+ notifyItemChanged(position)
1506
+ }
1507
+ }
1508
+ }
1509
+ return@launch
1510
+ }
1511
+ val bmp = renderPageBitmap(pdf, position, viewWidth)
1450
1512
  val pdfW = pagePdfW.getOrElse(position) { 1 }.toFloat()
1451
1513
  val pdfH = pagePdfH.getOrElse(position) { 1 }.toFloat()
1452
1514
  withContext(Dispatchers.Main) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@june24/expo-pdf-reader",
3
- "version": "0.1.28",
3
+ "version": "0.1.29",
4
4
  "description": "A PDF reader for Expo apps with annotation and zoom controls",
5
5
  "homepage": "git@gitlab.com:june_241/expo-pdf-reader.git",
6
6
  "main": "build/index.js",