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.
- package/README.md +306 -0
- package/android/build.gradle +76 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/pdfrender/ComposeRenderer.kt +85 -0
- package/android/src/main/java/com/pdfrender/PdfCacheManager.kt +150 -0
- package/android/src/main/java/com/pdfrender/PdfConstants.kt +63 -0
- package/android/src/main/java/com/pdfrender/PdfIconComponents.kt +275 -0
- package/android/src/main/java/com/pdfrender/PdfRenderingLogic.kt +325 -0
- package/android/src/main/java/com/pdfrender/PdfUIComponents.kt +335 -0
- package/android/src/main/java/com/pdfrender/PdfViewPackage.kt +32 -0
- package/android/src/main/java/com/pdfrender/PdfViewerActivity.kt +3467 -0
- package/android/src/main/java/com/pdfrender/PdfViewerFabricManager.kt +244 -0
- package/android/src/main/java/com/pdfrender/PdfViewerFragment.kt +129 -0
- package/android/src/main/java/com/pdfrender/PdfViewerTurboModule.kt +158 -0
- package/android/src/main/java/com/pdfrender/events/FullScreenChangeEvent.kt +26 -0
- package/android/src/main/java/com/pdfrender/events/LeftScreenChangeEvent.kt +22 -0
- package/android/src/main/java/com/pdfrender/events/RightScreenChangeEvent.kt +22 -0
- package/android/src/main/java/com/pdfrender/events/ZoomChangeEvent.kt +22 -0
- package/ios/PdfCacheManager.swift +44 -0
- package/ios/PdfConstants.swift +38 -0
- package/ios/PdfPageView.swift +121 -0
- package/ios/PdfRenderingLogic.swift +107 -0
- package/ios/PdfToolbarView.swift +158 -0
- package/ios/PdfViewerComponentView.mm +194 -0
- package/ios/PdfViewerTurboModule.mm +186 -0
- package/ios/PdfViewerTurboModuleImpl.swift +141 -0
- package/ios/PdfViewerView.swift +268 -0
- package/ios/PdfViewerViewController.swift +109 -0
- package/lib/commonjs/PdfViewerView.js +105 -0
- package/lib/commonjs/PdfViewerView.js.map +1 -0
- package/lib/commonjs/index.js +28 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/specs/NativePdfViewerComponent.js +27 -0
- package/lib/commonjs/specs/NativePdfViewerComponent.js.map +1 -0
- package/lib/commonjs/specs/NativePdfViewerModule.js +21 -0
- package/lib/commonjs/specs/NativePdfViewerModule.js.map +1 -0
- package/lib/commonjs/usePdfViewer.js +65 -0
- package/lib/commonjs/usePdfViewer.js.map +1 -0
- package/lib/module/PdfViewerView.js +99 -0
- package/lib/module/PdfViewerView.js.map +1 -0
- package/lib/module/index.js +8 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/specs/NativePdfViewerComponent.js +26 -0
- package/lib/module/specs/NativePdfViewerComponent.js.map +1 -0
- package/lib/module/specs/NativePdfViewerModule.js +18 -0
- package/lib/module/specs/NativePdfViewerModule.js.map +1 -0
- package/lib/module/usePdfViewer.js +60 -0
- package/lib/module/usePdfViewer.js.map +1 -0
- package/lib/typescript/PdfViewerView.d.ts +58 -0
- package/lib/typescript/PdfViewerView.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +7 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/specs/NativePdfViewerComponent.d.ts +59 -0
- package/lib/typescript/specs/NativePdfViewerComponent.d.ts.map +1 -0
- package/lib/typescript/specs/NativePdfViewerModule.d.ts +47 -0
- package/lib/typescript/specs/NativePdfViewerModule.d.ts.map +1 -0
- package/lib/typescript/usePdfViewer.d.ts +45 -0
- package/lib/typescript/usePdfViewer.d.ts.map +1 -0
- package/package.json +109 -0
- package/react-native-pdfrender.podspec +35 -0
- package/react-native.config.js +11 -0
- package/src/PdfViewerView.tsx +159 -0
- package/src/index.tsx +10 -0
- package/src/specs/NativePdfViewerComponent.ts +94 -0
- package/src/specs/NativePdfViewerModule.ts +58 -0
- 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
|
+
}
|