react-native-pdfrender 0.1.0

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.
Files changed (68) hide show
  1. package/README.md +306 -0
  2. package/android/build.gradle +76 -0
  3. package/android/src/main/AndroidManifest.xml +2 -0
  4. package/android/src/main/java/com/pdfrender/ComposeRenderer.kt +85 -0
  5. package/android/src/main/java/com/pdfrender/PdfCacheManager.kt +150 -0
  6. package/android/src/main/java/com/pdfrender/PdfConstants.kt +63 -0
  7. package/android/src/main/java/com/pdfrender/PdfIconComponents.kt +275 -0
  8. package/android/src/main/java/com/pdfrender/PdfRenderingLogic.kt +325 -0
  9. package/android/src/main/java/com/pdfrender/PdfUIComponents.kt +335 -0
  10. package/android/src/main/java/com/pdfrender/PdfViewPackage.kt +32 -0
  11. package/android/src/main/java/com/pdfrender/PdfViewerActivity.kt +3467 -0
  12. package/android/src/main/java/com/pdfrender/PdfViewerFabricManager.kt +244 -0
  13. package/android/src/main/java/com/pdfrender/PdfViewerFragment.kt +129 -0
  14. package/android/src/main/java/com/pdfrender/PdfViewerTurboModule.kt +158 -0
  15. package/android/src/main/java/com/pdfrender/events/FullScreenChangeEvent.kt +26 -0
  16. package/android/src/main/java/com/pdfrender/events/LeftScreenChangeEvent.kt +22 -0
  17. package/android/src/main/java/com/pdfrender/events/RightScreenChangeEvent.kt +22 -0
  18. package/android/src/main/java/com/pdfrender/events/ZoomChangeEvent.kt +22 -0
  19. package/ios/PdfCacheManager.swift +44 -0
  20. package/ios/PdfConstants.swift +38 -0
  21. package/ios/PdfPageView.swift +121 -0
  22. package/ios/PdfRenderingLogic.swift +107 -0
  23. package/ios/PdfToolbarView.swift +158 -0
  24. package/ios/PdfViewerComponentView.mm +194 -0
  25. package/ios/PdfViewerTurboModule.mm +186 -0
  26. package/ios/PdfViewerTurboModuleImpl.swift +141 -0
  27. package/ios/PdfViewerView.swift +268 -0
  28. package/ios/PdfViewerViewController.swift +109 -0
  29. package/lib/commonjs/PdfViewerView.js +105 -0
  30. package/lib/commonjs/PdfViewerView.js.map +1 -0
  31. package/lib/commonjs/index.js +28 -0
  32. package/lib/commonjs/index.js.map +1 -0
  33. package/lib/commonjs/package.json +1 -0
  34. package/lib/commonjs/specs/NativePdfViewerComponent.js +27 -0
  35. package/lib/commonjs/specs/NativePdfViewerComponent.js.map +1 -0
  36. package/lib/commonjs/specs/NativePdfViewerModule.js +21 -0
  37. package/lib/commonjs/specs/NativePdfViewerModule.js.map +1 -0
  38. package/lib/commonjs/usePdfViewer.js +65 -0
  39. package/lib/commonjs/usePdfViewer.js.map +1 -0
  40. package/lib/module/PdfViewerView.js +99 -0
  41. package/lib/module/PdfViewerView.js.map +1 -0
  42. package/lib/module/index.js +8 -0
  43. package/lib/module/index.js.map +1 -0
  44. package/lib/module/package.json +1 -0
  45. package/lib/module/specs/NativePdfViewerComponent.js +26 -0
  46. package/lib/module/specs/NativePdfViewerComponent.js.map +1 -0
  47. package/lib/module/specs/NativePdfViewerModule.js +18 -0
  48. package/lib/module/specs/NativePdfViewerModule.js.map +1 -0
  49. package/lib/module/usePdfViewer.js +60 -0
  50. package/lib/module/usePdfViewer.js.map +1 -0
  51. package/lib/typescript/PdfViewerView.d.ts +58 -0
  52. package/lib/typescript/PdfViewerView.d.ts.map +1 -0
  53. package/lib/typescript/index.d.ts +7 -0
  54. package/lib/typescript/index.d.ts.map +1 -0
  55. package/lib/typescript/specs/NativePdfViewerComponent.d.ts +59 -0
  56. package/lib/typescript/specs/NativePdfViewerComponent.d.ts.map +1 -0
  57. package/lib/typescript/specs/NativePdfViewerModule.d.ts +47 -0
  58. package/lib/typescript/specs/NativePdfViewerModule.d.ts.map +1 -0
  59. package/lib/typescript/usePdfViewer.d.ts +45 -0
  60. package/lib/typescript/usePdfViewer.d.ts.map +1 -0
  61. package/package.json +109 -0
  62. package/react-native-pdfrender.podspec +35 -0
  63. package/react-native.config.js +11 -0
  64. package/src/PdfViewerView.tsx +159 -0
  65. package/src/index.tsx +10 -0
  66. package/src/specs/NativePdfViewerComponent.ts +94 -0
  67. package/src/specs/NativePdfViewerModule.ts +58 -0
  68. package/src/usePdfViewer.ts +102 -0
@@ -0,0 +1,335 @@
1
+ package com.pdfrender
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.layout.*
5
+ import androidx.compose.foundation.shape.RoundedCornerShape
6
+ import androidx.compose.material.*
7
+ import androidx.compose.runtime.Composable
8
+ import androidx.compose.ui.Alignment
9
+ import androidx.compose.ui.Modifier
10
+ import androidx.compose.ui.graphics.Color
11
+ import androidx.compose.ui.text.font.FontFamily
12
+ import androidx.compose.ui.unit.dp
13
+ import androidx.compose.ui.unit.sp
14
+
15
+ /**
16
+ * PDF Viewer UI Components
17
+ *
18
+ * This file contains reusable UI components for the PDF viewer,
19
+ * including the top bar, zoom controls, and loading screens.
20
+ */
21
+
22
+ /**
23
+ * Top App Bar with zoom controls
24
+ *
25
+ * Displays the PDF title, page count, and zoom control buttons
26
+ *
27
+ * @param isInitialLoading Whether the PDF is still loading
28
+ * @param pageCount Total number of pages in the PDF
29
+ * @param scale Current zoom scale (0.3f to 0.6f)
30
+ * @param onScaleChange Callback when scale changes
31
+ */
32
+ @Composable
33
+ fun PdfViewerTopBar(
34
+ isInitialLoading: Boolean,
35
+ pageCount: Int,
36
+ scale: Float,
37
+ onScaleChange: (Float) -> Unit
38
+ ) {
39
+ Column {
40
+ TopAppBar(
41
+ title = {
42
+ Text(
43
+ if (isInitialLoading) "Loading PDF..."
44
+ else "PDF Viewer - $pageCount pages"
45
+ )
46
+ },
47
+ actions = {
48
+ if (!isInitialLoading && pageCount > 0) {
49
+ // Zoom In Button
50
+ Button(
51
+ onClick = {
52
+ // Use MAX_SCALE_SMALL_SCREEN as default (conservative for phones)
53
+ // In practice, maxZoom should be passed as parameter based on screen size
54
+ onScaleChange((scale + PdfViewerConfig.SCALE_STEP).coerceAtMost(PdfViewerConfig.MAX_SCALE_SMALL_SCREEN))
55
+ },
56
+ modifier = Modifier.padding(horizontal = 4.dp)
57
+ ) {
58
+ Text("Zoom In")
59
+ }
60
+
61
+ // Zoom Out Button
62
+ Button(
63
+ onClick = {
64
+ onScaleChange((scale - PdfViewerConfig.SCALE_STEP).coerceAtLeast(PdfViewerConfig.MIN_SCALE))
65
+ },
66
+ modifier = Modifier.padding(horizontal = 4.dp)
67
+ ) {
68
+ Text("Zoom Out")
69
+ }
70
+
71
+ // Reset Button
72
+ Button(
73
+ onClick = {
74
+ onScaleChange(PdfViewerConfig.DEFAULT_SCALE)
75
+ },
76
+ modifier = Modifier.padding(horizontal = 4.dp)
77
+ ) {
78
+ Text("Reset")
79
+ }
80
+ }
81
+ }
82
+ )
83
+
84
+ // Loading Progress Indicator
85
+ if (isInitialLoading) {
86
+ LinearProgressIndicator(
87
+ modifier = Modifier.fillMaxWidth()
88
+ )
89
+ }
90
+
91
+ // Zoom Slider Control
92
+ if (!isInitialLoading && pageCount > 0) {
93
+ ZoomSlider(
94
+ scale = scale,
95
+ onScaleChange = onScaleChange
96
+ )
97
+ }
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Zoom slider component for controlling PDF zoom level
103
+ *
104
+ * @param scale Current zoom scale (0.3f to 0.6f)
105
+ * @param onScaleChange Callback when scale changes
106
+ */
107
+ @Composable
108
+ fun ZoomSlider(
109
+ scale: Float,
110
+ onScaleChange: (Float) -> Unit
111
+ ) {
112
+ Card(
113
+ modifier = Modifier
114
+ .fillMaxWidth()
115
+ .padding(horizontal = 16.dp, vertical = 8.dp),
116
+ elevation = 4.dp
117
+ ) {
118
+ Column(
119
+ modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
120
+ ) {
121
+ // Zoom Level Display
122
+ Row(
123
+ modifier = Modifier.fillMaxWidth(),
124
+ horizontalArrangement = Arrangement.SpaceBetween,
125
+ verticalAlignment = Alignment.CenterVertically
126
+ ) {
127
+ Text(
128
+ text = "Zoom Level:",
129
+ style = MaterialTheme.typography.body2
130
+ )
131
+ Text(
132
+ text = "${(scale * 100).toInt()}%",
133
+ style = MaterialTheme.typography.body1,
134
+ modifier = Modifier.padding(horizontal = 8.dp)
135
+ )
136
+ }
137
+
138
+ // Zoom Slider
139
+ Slider(
140
+ value = scale,
141
+ onValueChange = { newScale ->
142
+ // Round to nearest 5% to avoid too many re-renders
143
+ val rounded = (kotlin.math.round(newScale * 20f) / 20f)
144
+ // Only update if actually changed
145
+ if (kotlin.math.abs(scale - rounded) > 0.01f) {
146
+ onScaleChange(rounded)
147
+ }
148
+ },
149
+ valueRange = PdfViewerConfig.MIN_SCALE..PdfViewerConfig.MAX_SCALE_SMALL_SCREEN,
150
+ steps = 5, // Creates 5% increments: 30%, 35%, 40%, 45%, 50%, 55%, 60%
151
+ modifier = Modifier.fillMaxWidth()
152
+ )
153
+
154
+ // Scale Labels
155
+ Row(
156
+ modifier = Modifier.fillMaxWidth(),
157
+ horizontalArrangement = Arrangement.SpaceBetween
158
+ ) {
159
+ Text(
160
+ text = "${(PdfViewerConfig.MIN_SCALE * 100).toInt()}%",
161
+ style = MaterialTheme.typography.caption
162
+ )
163
+ Text(
164
+ text = "${(PdfViewerConfig.MAX_SCALE_SMALL_SCREEN * 100).toInt()}%",
165
+ style = MaterialTheme.typography.caption
166
+ )
167
+ }
168
+ }
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Loading screen displayed while PDF is being loaded
174
+ *
175
+ * @param loadingStatus Current loading status message
176
+ * @param loadingProgress Loading progress (0-100)
177
+ * @param pageCount Total number of pages (if known)
178
+ */
179
+ @Composable
180
+ fun PdfLoadingScreen(
181
+ loadingStatus: String,
182
+ loadingProgress: Int,
183
+ pageCount: Int = 0
184
+ ) {
185
+ Box(
186
+ modifier = Modifier.fillMaxSize(),
187
+ contentAlignment = Alignment.Center
188
+ ) {
189
+ Column(
190
+ horizontalAlignment = Alignment.CenterHorizontally,
191
+ verticalArrangement = Arrangement.Center,
192
+ modifier = Modifier.padding(32.dp)
193
+ ) {
194
+ CircularProgressIndicator(
195
+ modifier = Modifier.size(64.dp)
196
+ )
197
+ Spacer(modifier = Modifier.height(24.dp))
198
+ Text(
199
+ text = loadingStatus,
200
+ style = MaterialTheme.typography.h6
201
+ )
202
+ Spacer(modifier = Modifier.height(16.dp))
203
+ LinearProgressIndicator(
204
+ progress = loadingProgress / 100f,
205
+ modifier = Modifier
206
+ .fillMaxWidth(0.7f)
207
+ .height(8.dp)
208
+ )
209
+ Spacer(modifier = Modifier.height(8.dp))
210
+ Text(
211
+ text = "$loadingProgress%",
212
+ style = MaterialTheme.typography.body1
213
+ )
214
+ if (pageCount > 0) {
215
+ Spacer(modifier = Modifier.height(8.dp))
216
+ Text(
217
+ text = "$pageCount pages",
218
+ style = MaterialTheme.typography.caption,
219
+ color = androidx.compose.ui.graphics.Color.Gray
220
+ )
221
+ }
222
+ }
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Rendering Performance Statistics Display (Debug Mode)
228
+ *
229
+ * Shows real-time rendering performance metrics including:
230
+ * - Average rendering time
231
+ * - Page opening time
232
+ * - Bitmap creation time
233
+ * - PDF render time
234
+ *
235
+ * @param renderingStats The RenderingStats instance to display
236
+ * @param showStats Whether to show the stats panel (default: true in debug builds)
237
+ */
238
+ @Composable
239
+ fun RenderingStatsPanel(
240
+ renderingStats: RenderingStats,
241
+ showStats: Boolean = true
242
+ ) {
243
+ if (!showStats) return
244
+
245
+ Card(
246
+ modifier = Modifier
247
+ .fillMaxWidth()
248
+ .padding(horizontal = 16.dp, vertical = 8.dp),
249
+ elevation = 8.dp,
250
+ backgroundColor = Color(0xFF1E1E1E),
251
+ shape = RoundedCornerShape(8.dp)
252
+ ) {
253
+ Column(
254
+ modifier = Modifier.padding(12.dp)
255
+ ) {
256
+ // Header
257
+ Row(
258
+ modifier = Modifier.fillMaxWidth(),
259
+ horizontalArrangement = Arrangement.SpaceBetween,
260
+ verticalAlignment = Alignment.CenterVertically
261
+ ) {
262
+ Text(
263
+ text = "⚡ Rendering Performance",
264
+ style = MaterialTheme.typography.subtitle1.copy(
265
+ color = Color(0xFF4CAF50),
266
+ fontWeight = androidx.compose.ui.text.font.FontWeight.Bold
267
+ )
268
+ )
269
+ }
270
+
271
+ Spacer(modifier = Modifier.height(8.dp))
272
+ Divider(color = Color(0xFF424242))
273
+ Spacer(modifier = Modifier.height(8.dp))
274
+
275
+ // Stats content
276
+ val statsText = renderingStats.getStats()
277
+ if (statsText.contains("No render")) {
278
+ Text(
279
+ text = "No rendering data yet...",
280
+ style = MaterialTheme.typography.caption.copy(
281
+ color = Color(0xFF9E9E9E),
282
+ fontFamily = FontFamily.Monospace
283
+ )
284
+ )
285
+ } else {
286
+ // Parse and display stats in a formatted way
287
+ Text(
288
+ text = statsText,
289
+ style = MaterialTheme.typography.caption.copy(
290
+ color = Color(0xFFE0E0E0),
291
+ fontFamily = FontFamily.Monospace,
292
+ fontSize = 11.sp,
293
+ lineHeight = 16.sp
294
+ )
295
+ )
296
+ }
297
+ }
298
+ }
299
+ }
300
+
301
+ /**
302
+ * Compact rendering time indicator for individual pages
303
+ *
304
+ * Displays a small badge showing the render time for a specific page
305
+ *
306
+ * @param renderTimeMs The rendering time in milliseconds
307
+ * @param visible Whether to show the indicator
308
+ */
309
+ @Composable
310
+ fun PageRenderTimeIndicator(
311
+ renderTimeMs: Long,
312
+ visible: Boolean = true
313
+ ) {
314
+ if (!visible) return
315
+
316
+ Surface(
317
+ modifier = Modifier.padding(8.dp),
318
+ shape = RoundedCornerShape(4.dp),
319
+ color = when {
320
+ renderTimeMs < 100 -> Color(0xFF4CAF50) // Green for fast
321
+ renderTimeMs < 300 -> Color(0xFFFFC107) // Yellow for medium
322
+ else -> Color(0xFFF44336) // Red for slow
323
+ }.copy(alpha = 0.8f)
324
+ ) {
325
+ Text(
326
+ text = "${renderTimeMs}ms",
327
+ modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp),
328
+ style = MaterialTheme.typography.caption.copy(
329
+ color = Color.White,
330
+ fontSize = 10.sp,
331
+ fontFamily = FontFamily.Monospace
332
+ )
333
+ )
334
+ }
335
+ }
@@ -0,0 +1,32 @@
1
+ package com.pdfrender
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+ /**
9
+ * PdfViewPackage
10
+ *
11
+ * Registers both new-arch components with the React Native runtime:
12
+ * • PdfViewerTurboModule — headless module (openPdfViewer, getPdfPageCount, createPdf…)
13
+ * • PdfViewerFabricManager — embedded Fabric view (<PdfViewerView /> from JS)
14
+ *
15
+ * Previously only the stub PdfViewModule and an empty ViewManager list were registered.
16
+ * The old PdfViewModule is no longer registered here — it's superseded by PdfViewerTurboModule.
17
+ */
18
+ class PdfViewPackage : ReactPackage {
19
+
20
+ @Suppress("OVERRIDE_DEPRECATION")
21
+ override fun createNativeModules(
22
+ reactContext: ReactApplicationContext
23
+ ): List<NativeModule> = listOf(
24
+ PdfViewerTurboModule(reactContext)
25
+ )
26
+
27
+ override fun createViewManagers(
28
+ reactContext: ReactApplicationContext
29
+ ): List<ViewManager<*, *>> = listOf(
30
+ PdfViewerFabricManager()
31
+ )
32
+ }