@papyrus-sdk/engine-native 0.1.1 → 0.1.3

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 (26) hide show
  1. package/LICENSE +21 -0
  2. package/android/build.gradle +40 -40
  3. package/android/src/main/AndroidManifest.xml +3 -3
  4. package/android/src/main/java/com/papyrus/engine/PapyrusEngineStore.java +71 -71
  5. package/android/src/main/java/com/papyrus/engine/PapyrusNativeEngineModule.java +533 -509
  6. package/android/src/main/java/com/papyrus/engine/PapyrusNativeEngineModule.kt +561 -0
  7. package/android/src/main/java/com/papyrus/engine/PapyrusOutline.java +20 -20
  8. package/android/src/main/java/com/papyrus/engine/PapyrusOutlineItem.java +13 -13
  9. package/android/src/main/java/com/papyrus/engine/PapyrusPackage.java +24 -24
  10. package/android/src/main/java/com/papyrus/engine/PapyrusPageView.java +86 -86
  11. package/android/src/main/java/com/papyrus/engine/PapyrusPageViewManager.java +16 -16
  12. package/android/src/main/java/com/papyrus/engine/PapyrusPageViewModule.kt +12 -0
  13. package/android/src/main/java/com/papyrus/engine/PapyrusTextHit.java +15 -15
  14. package/android/src/main/java/com/papyrus/engine/PapyrusTextSearch.java +20 -20
  15. package/android/src/main/java/com/papyrus/engine/PapyrusTextSelect.java +20 -20
  16. package/android/src/main/java/com/papyrus/engine/PapyrusTextSelection.java +11 -11
  17. package/dist/index.d.mts +8 -7
  18. package/dist/index.d.ts +8 -7
  19. package/dist/index.js +213 -8
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +214 -9
  22. package/dist/index.mjs.map +1 -1
  23. package/ios/PapyrusNativeEngine.podspec +1 -1
  24. package/ios/PapyrusPageViewManager.m +19 -19
  25. package/package.json +30 -30
  26. package/react-native.config.js +10 -10
@@ -0,0 +1,561 @@
1
+ package com.papyrus.engine
2
+
3
+ import android.content.ContentResolver
4
+ import android.content.Context
5
+ import android.net.Uri
6
+ import android.os.ParcelFileDescriptor
7
+ import android.view.View
8
+ import com.facebook.react.bridge.UiThreadUtil
9
+ import com.shockwave.pdfium.PdfDocument
10
+ import expo.modules.kotlin.Promise
11
+ import expo.modules.kotlin.modules.Module
12
+ import expo.modules.kotlin.modules.ModuleDefinition
13
+ import expo.modules.kotlin.typedarray.Uint8Array
14
+ import java.io.File
15
+ import java.io.FileOutputStream
16
+ import java.io.IOException
17
+ import java.io.InputStream
18
+ import java.lang.reflect.Method
19
+ import java.net.HttpURLConnection
20
+ import java.net.URL
21
+ import java.util.concurrent.ExecutorService
22
+ import java.util.concurrent.Executors
23
+
24
+ class PapyrusNativeEngineModule : Module() {
25
+ private val executor: ExecutorService = Executors.newSingleThreadExecutor()
26
+
27
+ override fun definition() = ModuleDefinition {
28
+ Name("PapyrusNativeEngine")
29
+
30
+ Function("createEngine") {
31
+ val context = appContext.reactContext ?: return@Function "default"
32
+ PapyrusEngineStore.createEngine(context)
33
+ }
34
+
35
+ Function("destroyEngine") { engineId: String ->
36
+ PapyrusEngineStore.destroyEngine(engineId)
37
+ }
38
+
39
+ AsyncFunction("load") { engineId: String, source: Map<String, Any?>, promise: Promise ->
40
+ executor.execute {
41
+ try {
42
+ val state = PapyrusEngineStore.getEngine(engineId)
43
+ if (state == null) {
44
+ promise.reject("papyrus_no_engine", "Engine not found", null)
45
+ return@execute
46
+ }
47
+
48
+ val context = appContext.reactContext ?: throw IllegalStateException("React context missing")
49
+ val file = materializeSource(source, context)
50
+ if (file == null) {
51
+ promise.reject("papyrus_invalid_source", "Unsupported PDF source", null)
52
+ return@execute
53
+ }
54
+
55
+ val fd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
56
+ val document = state.pdfium.newDocument(fd)
57
+ PapyrusEngineStore.setDocument(state, document, fd, file.absolutePath)
58
+
59
+ val pageCount = state.pdfium.getPageCount(document)
60
+ promise.resolve(mapOf("pageCount" to pageCount))
61
+ } catch (error: Throwable) {
62
+ promise.reject("papyrus_load_failed", error.message, error)
63
+ }
64
+ }
65
+ }
66
+
67
+ Function("getPageCount") { engineId: String ->
68
+ val state = PapyrusEngineStore.getEngine(engineId)
69
+ if (state == null || state.document == null) return@Function 0
70
+ state.pdfium.getPageCount(state.document)
71
+ }
72
+
73
+ AsyncFunction("renderPage") { engineId: String, pageIndex: Int, target: Int, scale: Double, zoom: Double, rotation: Int ->
74
+ val state = PapyrusEngineStore.getEngine(engineId) ?: return@AsyncFunction
75
+ UiThreadUtil.runOnUiThread {
76
+ val view = appContext.findView<View>(target)
77
+ if (view is PapyrusPageView) {
78
+ view.render(state, pageIndex, scale.toFloat(), zoom.toFloat(), rotation)
79
+ }
80
+ }
81
+ }
82
+
83
+ AsyncFunction("renderTextLayer") { engineId: String, pageIndex: Int, target: Int, scale: Double, zoom: Double, rotation: Int ->
84
+ // no-op
85
+ Unit
86
+ }
87
+
88
+ AsyncFunction("getTextContent") { engineId: String, pageIndex: Int, promise: Promise ->
89
+ executor.execute {
90
+ val state = PapyrusEngineStore.getEngine(engineId)
91
+ if (state == null || state.document == null) {
92
+ promise.resolve(emptyList<Any>())
93
+ return@execute
94
+ }
95
+ val text = synchronized(state.pdfiumLock) { extractPageText(state, pageIndex) }
96
+ val items = mutableListOf<Map<String, Any>>()
97
+ if (!text.isNullOrEmpty()) {
98
+ items.add(
99
+ mapOf(
100
+ "str" to text,
101
+ "dir" to "ltr",
102
+ "width" to 0,
103
+ "height" to 0,
104
+ "transform" to listOf(1, 0, 0, 1, 0, 0),
105
+ "fontName" to ""
106
+ )
107
+ )
108
+ }
109
+ promise.resolve(items)
110
+ }
111
+ }
112
+
113
+ AsyncFunction("getPageDimensions") { engineId: String, pageIndex: Int, promise: Promise ->
114
+ executor.execute {
115
+ val state = PapyrusEngineStore.getEngine(engineId)
116
+ if (state == null || state.document == null) {
117
+ promise.resolve(mapOf("width" to 0, "height" to 0))
118
+ return@execute
119
+ }
120
+ val (width, height) = synchronized(state.pdfiumLock) {
121
+ val w = state.pdfium.getPageWidthPoint(state.document, pageIndex)
122
+ val h = state.pdfium.getPageHeightPoint(state.document, pageIndex)
123
+ Pair(w, h)
124
+ }
125
+ promise.resolve(mapOf("width" to width, "height" to height))
126
+ }
127
+ }
128
+
129
+ AsyncFunction("getOutline") { engineId: String, promise: Promise ->
130
+ executor.execute {
131
+ val state = PapyrusEngineStore.getEngine(engineId)
132
+ if (state == null || state.document == null) {
133
+ promise.resolve(emptyList<Any>())
134
+ return@execute
135
+ }
136
+
137
+ var items: Array<PapyrusOutlineItem>? = null
138
+ try {
139
+ if (PapyrusOutline.AVAILABLE) {
140
+ if (!state.sourcePath.isNullOrEmpty()) {
141
+ synchronized(state.pdfiumLock) {
142
+ items = PapyrusOutline.nativeGetOutlineFile(state.sourcePath)
143
+ }
144
+ } else {
145
+ val docPtr = synchronized(state.pdfiumLock) { extractNativeDocPointer(state.document) }
146
+ if (docPtr != 0L) {
147
+ synchronized(state.pdfiumLock) {
148
+ items = PapyrusOutline.nativeGetOutline(docPtr)
149
+ }
150
+ }
151
+ }
152
+ }
153
+ } catch (_: Throwable) {
154
+ items = null
155
+ }
156
+
157
+ val result = mutableListOf<Map<String, Any?>>()
158
+ items?.forEach { item ->
159
+ result.add(serializeOutlineItem(item))
160
+ }
161
+ promise.resolve(result)
162
+ }
163
+ }
164
+
165
+ AsyncFunction("getPageIndex") { engineId: String, dest: Map<String, Any?>, promise: Promise ->
166
+ val kind = dest["kind"] as? String
167
+ val value = dest["value"]
168
+
169
+ if (kind == "pageIndex" && value is Number) {
170
+ promise.resolve(value.toInt())
171
+ return@AsyncFunction
172
+ }
173
+
174
+ if (kind == "pageNumber" && value is Number) {
175
+ promise.resolve(maxOf(0, value.toInt() - 1))
176
+ return@AsyncFunction
177
+ }
178
+
179
+ promise.resolve(null)
180
+ }
181
+
182
+ AsyncFunction("searchText") { engineId: String, query: String, promise: Promise ->
183
+ executor.execute {
184
+ val state = PapyrusEngineStore.getEngine(engineId)
185
+ if (state == null || state.document == null || query.length < 2) {
186
+ promise.resolve(emptyList<Any>())
187
+ return@execute
188
+ }
189
+
190
+ val pageCount = state.pdfium.getPageCount(state.document)
191
+ state.isSearching = true
192
+ try {
193
+ try {
194
+ if (PapyrusTextSearch.AVAILABLE) {
195
+ var hits: Array<PapyrusTextHit>? = null
196
+ if (!state.sourcePath.isNullOrEmpty()) {
197
+ synchronized(state.pdfiumLock) {
198
+ hits = PapyrusTextSearch.nativeSearchFile(state.sourcePath, query)
199
+ }
200
+ } else {
201
+ val docPtr = synchronized(state.pdfiumLock) { extractNativeDocPointer(state.document) }
202
+ if (docPtr != 0L) {
203
+ synchronized(state.pdfiumLock) {
204
+ hits = PapyrusTextSearch.nativeSearch(docPtr, pageCount, query)
205
+ }
206
+ }
207
+ }
208
+
209
+ if (!hits.isNullOrEmpty()) {
210
+ val results = mutableListOf<Map<String, Any?>>()
211
+ hits?.forEach { hit ->
212
+ val result = mutableMapOf<String, Any?>(
213
+ "pageIndex" to hit.pageIndex,
214
+ "text" to (hit.text ?: query),
215
+ "matchIndex" to hit.matchIndex
216
+ )
217
+ val rects = hit.rects
218
+ if (rects != null && rects.size >= 4) {
219
+ val rectList = mutableListOf<Map<String, Any>>()
220
+ var i = 0
221
+ while (i + 3 < rects.size) {
222
+ rectList.add(
223
+ mapOf(
224
+ "x" to rects[i],
225
+ "y" to rects[i + 1],
226
+ "width" to rects[i + 2],
227
+ "height" to rects[i + 3]
228
+ )
229
+ )
230
+ i += 4
231
+ }
232
+ result["rects"] = rectList
233
+ }
234
+ results.add(result)
235
+ }
236
+ promise.resolve(results)
237
+ return@execute
238
+ }
239
+ }
240
+ } catch (_: Throwable) {
241
+ }
242
+
243
+ val normalizedQuery = query.lowercase()
244
+ val results = mutableListOf<Map<String, Any?>>()
245
+
246
+ for (pageIndex in 0 until pageCount) {
247
+ val text = synchronized(state.pdfiumLock) { extractPageText(state, pageIndex) } ?: ""
248
+ if (text.isEmpty()) continue
249
+
250
+ val lower = text.lowercase()
251
+ var pos = lower.indexOf(normalizedQuery)
252
+ var matchIndex = 0
253
+ while (pos != -1) {
254
+ val start = maxOf(0, pos - 20)
255
+ val end = minOf(text.length, pos + normalizedQuery.length + 20)
256
+ val preview = text.substring(start, end)
257
+
258
+ results.add(
259
+ mapOf(
260
+ "pageIndex" to pageIndex,
261
+ "text" to preview,
262
+ "matchIndex" to matchIndex++
263
+ )
264
+ )
265
+
266
+ pos = lower.indexOf(normalizedQuery, pos + 1)
267
+ }
268
+ }
269
+
270
+ promise.resolve(results)
271
+ } finally {
272
+ state.isSearching = false
273
+ }
274
+ }
275
+ }
276
+
277
+ AsyncFunction("selectText") { engineId: String, pageIndex: Int, x: Double, y: Double, width: Double, height: Double, promise: Promise ->
278
+ executor.execute {
279
+ val state = PapyrusEngineStore.getEngine(engineId)
280
+ if (state == null || state.document == null || pageIndex < 0) {
281
+ promise.resolve(null)
282
+ return@execute
283
+ }
284
+
285
+ if (!PapyrusTextSelect.AVAILABLE) {
286
+ promise.resolve(null)
287
+ return@execute
288
+ }
289
+
290
+ var selection: PapyrusTextSelection? = null
291
+ try {
292
+ if (!state.sourcePath.isNullOrEmpty()) {
293
+ synchronized(state.pdfiumLock) {
294
+ selection = PapyrusTextSelect.nativeSelectTextFile(
295
+ state.sourcePath,
296
+ pageIndex,
297
+ x.toFloat(),
298
+ y.toFloat(),
299
+ width.toFloat(),
300
+ height.toFloat()
301
+ )
302
+ }
303
+ } else {
304
+ val docPtr = synchronized(state.pdfiumLock) { extractNativeDocPointer(state.document) }
305
+ if (docPtr != 0L) {
306
+ synchronized(state.pdfiumLock) {
307
+ selection = PapyrusTextSelect.nativeSelectText(
308
+ docPtr,
309
+ pageIndex,
310
+ x.toFloat(),
311
+ y.toFloat(),
312
+ width.toFloat(),
313
+ height.toFloat()
314
+ )
315
+ }
316
+ }
317
+ }
318
+ } catch (_: Throwable) {
319
+ selection = null
320
+ }
321
+
322
+ val rects = selection?.rects
323
+ if (selection == null || rects == null || rects.isEmpty()) {
324
+ promise.resolve(null)
325
+ return@execute
326
+ }
327
+
328
+ val rectList = mutableListOf<Map<String, Any>>()
329
+ var i = 0
330
+ while (i + 3 < rects.size) {
331
+ rectList.add(
332
+ mapOf(
333
+ "x" to rects[i],
334
+ "y" to rects[i + 1],
335
+ "width" to rects[i + 2],
336
+ "height" to rects[i + 3]
337
+ )
338
+ )
339
+ i += 4
340
+ }
341
+
342
+ promise.resolve(
343
+ mapOf(
344
+ "text" to (selection?.text ?: ""),
345
+ "rects" to rectList
346
+ )
347
+ )
348
+ }
349
+ }
350
+ }
351
+
352
+ private fun extractPageText(state: PapyrusEngineStore.EngineState, pageIndex: Int): String? {
353
+ try {
354
+ state.pdfium.openPage(state.document, pageIndex)
355
+ } catch (_: Throwable) {
356
+ }
357
+
358
+ try {
359
+ var method: Method? = null
360
+ method = try {
361
+ state.pdfium.javaClass.getDeclaredMethod("getPageText", PdfDocument::class.java, Int::class.javaPrimitiveType)
362
+ } catch (_: NoSuchMethodException) {
363
+ null
364
+ }
365
+
366
+ if (method == null) {
367
+ method = try {
368
+ state.pdfium.javaClass.getDeclaredMethod("nativeGetPageText", Long::class.javaPrimitiveType, Int::class.javaPrimitiveType)
369
+ } catch (_: NoSuchMethodException) {
370
+ null
371
+ }
372
+ }
373
+
374
+ if (method != null) {
375
+ method.isAccessible = true
376
+ val result = if (method.parameterTypes.size == 2 && method.parameterTypes[0] == PdfDocument::class.java) {
377
+ method.invoke(state.pdfium, state.document, pageIndex)
378
+ } else if (method.parameterTypes.size == 2 && method.parameterTypes[0] == Long::class.javaPrimitiveType) {
379
+ val docPtr = extractNativeDocPointer(state.document)
380
+ method.invoke(state.pdfium, docPtr, pageIndex)
381
+ } else {
382
+ null
383
+ }
384
+ return result?.toString() ?: ""
385
+ }
386
+ } catch (_: Throwable) {
387
+ }
388
+
389
+ return ""
390
+ }
391
+
392
+ private fun extractNativeDocPointer(document: PdfDocument?): Long {
393
+ if (document == null) return 0L
394
+ return try {
395
+ val field = PdfDocument::class.java.getDeclaredField("mNativeDocPtr")
396
+ field.isAccessible = true
397
+ val value = field.get(document)
398
+ if (value is Long) value else 0L
399
+ } catch (_: Throwable) {
400
+ 0L
401
+ }
402
+ }
403
+
404
+ private fun serializeOutlineItem(item: PapyrusOutlineItem): Map<String, Any?> {
405
+ val map = mutableMapOf<String, Any?>(
406
+ "title" to (item.title ?: ""),
407
+ "pageIndex" to item.pageIndex
408
+ )
409
+ val children = item.children
410
+ if (children != null && children.isNotEmpty()) {
411
+ val childMaps = mutableListOf<Map<String, Any?>>()
412
+ children.forEach { child ->
413
+ childMaps.add(serializeOutlineItem(child))
414
+ }
415
+ map["children"] = childMaps
416
+ }
417
+ return map
418
+ }
419
+
420
+ @Throws(IOException::class)
421
+ private fun materializeSource(source: Map<String, Any?>, context: Context): File? {
422
+ val uriValue = source["uri"]
423
+ if (uriValue is String) {
424
+ if (uriValue.startsWith("http://") || uriValue.startsWith("https://")) {
425
+ return downloadToCache(uriValue, context)
426
+ }
427
+
428
+ if (uriValue.startsWith("asset:/")) {
429
+ return copyFromAsset(uriValue.substring("asset:/".length), context)
430
+ }
431
+
432
+ if (uriValue.startsWith("file:///android_asset/")) {
433
+ return copyFromAsset(uriValue.substring("file:///android_asset/".length), context)
434
+ }
435
+
436
+ if (uriValue.startsWith("content://")) {
437
+ return copyFromContentUri(Uri.parse(uriValue), context)
438
+ }
439
+
440
+ if (uriValue.startsWith("file://")) {
441
+ return File(Uri.parse(uriValue).path ?: return null)
442
+ }
443
+
444
+ if (uriValue.startsWith("res://")) {
445
+ val resourceName = uriValue.substring("res://".length)
446
+ val resourceId = context.resources.getIdentifier(resourceName, "raw", context.packageName)
447
+ if (resourceId != 0) {
448
+ return copyFromRawResource(resourceId, context)
449
+ }
450
+ }
451
+
452
+ val resourceId = context.resources.getIdentifier(uriValue, "raw", context.packageName)
453
+ if (resourceId != 0) {
454
+ return copyFromRawResource(resourceId, context)
455
+ }
456
+
457
+ return File(uriValue)
458
+ }
459
+
460
+ val dataValue = source["data"]
461
+ if (dataValue != null) {
462
+ val bytes = toByteArray(dataValue)
463
+ if (bytes != null) {
464
+ return writeBytesToCache(bytes, context)
465
+ }
466
+ }
467
+
468
+ return null
469
+ }
470
+
471
+ private fun toByteArray(value: Any): ByteArray? {
472
+ return when (value) {
473
+ is ByteArray -> value
474
+ is Uint8Array -> {
475
+ val bytes = ByteArray(value.byteLength)
476
+ value.read(bytes, 0, value.byteLength)
477
+ bytes
478
+ }
479
+ is List<*> -> {
480
+ val bytes = ByteArray(value.size)
481
+ value.forEachIndexed { index, item ->
482
+ val number = item as? Number ?: return null
483
+ bytes[index] = number.toInt().toByte()
484
+ }
485
+ bytes
486
+ }
487
+ else -> null
488
+ }
489
+ }
490
+
491
+ @Throws(IOException::class)
492
+ private fun downloadToCache(uri: String, context: Context): File {
493
+ val url = URL(uri)
494
+ val connection = url.openConnection() as HttpURLConnection
495
+ connection.connect()
496
+ if (connection.responseCode >= 400) {
497
+ throw IOException("Failed to download PDF")
498
+ }
499
+ val inputStream = connection.inputStream
500
+ val out = createTempFile(context)
501
+ writeStreamToFile(inputStream, out)
502
+ connection.disconnect()
503
+ return out
504
+ }
505
+
506
+ @Throws(IOException::class)
507
+ private fun copyFromContentUri(uri: Uri, context: Context): File {
508
+ val resolver: ContentResolver = context.contentResolver
509
+ val inputStream = resolver.openInputStream(uri) ?: throw IOException("Unable to read content URI")
510
+ val out = createTempFile(context)
511
+ writeStreamToFile(inputStream, out)
512
+ return out
513
+ }
514
+
515
+ @Throws(IOException::class)
516
+ private fun copyFromAsset(assetPath: String, context: Context): File {
517
+ val inputStream = context.assets.open(assetPath)
518
+ val out = createTempFile(context)
519
+ writeStreamToFile(inputStream, out)
520
+ return out
521
+ }
522
+
523
+ @Throws(IOException::class)
524
+ private fun copyFromRawResource(resourceId: Int, context: Context): File {
525
+ val inputStream = context.resources.openRawResource(resourceId)
526
+ val out = createTempFile(context)
527
+ writeStreamToFile(inputStream, out)
528
+ return out
529
+ }
530
+
531
+ @Throws(IOException::class)
532
+ private fun writeBytesToCache(bytes: ByteArray, context: Context): File {
533
+ val out = createTempFile(context)
534
+ FileOutputStream(out).use { fos ->
535
+ fos.write(bytes)
536
+ fos.flush()
537
+ }
538
+ return out
539
+ }
540
+
541
+ @Throws(IOException::class)
542
+ private fun createTempFile(context: Context): File {
543
+ val cacheDir = context.cacheDir
544
+ return File.createTempFile("papyrus", ".pdf", cacheDir)
545
+ }
546
+
547
+ @Throws(IOException::class)
548
+ private fun writeStreamToFile(inputStream: InputStream, out: File) {
549
+ FileOutputStream(out).use { fos ->
550
+ val buffer = ByteArray(8192)
551
+ var read: Int
552
+ while (true) {
553
+ read = inputStream.read(buffer)
554
+ if (read == -1) break
555
+ fos.write(buffer, 0, read)
556
+ }
557
+ fos.flush()
558
+ }
559
+ inputStream.close()
560
+ }
561
+ }
@@ -1,20 +1,20 @@
1
- package com.papyrus.engine;
2
-
3
- final class PapyrusOutline {
4
- static final boolean AVAILABLE;
5
-
6
- static {
7
- boolean available = false;
8
- try {
9
- System.loadLibrary("papyrus_text");
10
- available = true;
11
- } catch (Throwable ignored) {
12
- available = false;
13
- }
14
- AVAILABLE = available;
15
- }
16
-
17
- static native PapyrusOutlineItem[] nativeGetOutline(long docPtr);
18
-
19
- static native PapyrusOutlineItem[] nativeGetOutlineFile(String filePath);
20
- }
1
+ package com.papyrus.engine;
2
+
3
+ final class PapyrusOutline {
4
+ static final boolean AVAILABLE;
5
+
6
+ static {
7
+ boolean available = false;
8
+ try {
9
+ System.loadLibrary("papyrus_text");
10
+ available = true;
11
+ } catch (Throwable ignored) {
12
+ available = false;
13
+ }
14
+ AVAILABLE = available;
15
+ }
16
+
17
+ static native PapyrusOutlineItem[] nativeGetOutline(long docPtr);
18
+
19
+ static native PapyrusOutlineItem[] nativeGetOutlineFile(String filePath);
20
+ }
@@ -1,13 +1,13 @@
1
- package com.papyrus.engine;
2
-
3
- final class PapyrusOutlineItem {
4
- final String title;
5
- final int pageIndex;
6
- final PapyrusOutlineItem[] children;
7
-
8
- PapyrusOutlineItem(String title, int pageIndex, PapyrusOutlineItem[] children) {
9
- this.title = title != null ? title : "";
10
- this.pageIndex = pageIndex;
11
- this.children = children;
12
- }
13
- }
1
+ package com.papyrus.engine;
2
+
3
+ final class PapyrusOutlineItem {
4
+ final String title;
5
+ final int pageIndex;
6
+ final PapyrusOutlineItem[] children;
7
+
8
+ PapyrusOutlineItem(String title, int pageIndex, PapyrusOutlineItem[] children) {
9
+ this.title = title != null ? title : "";
10
+ this.pageIndex = pageIndex;
11
+ this.children = children;
12
+ }
13
+ }
@@ -1,24 +1,24 @@
1
- package com.papyrus.engine;
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
- import java.util.ArrayList;
9
- import java.util.Collections;
10
- import java.util.List;
11
-
12
- public class PapyrusPackage implements ReactPackage {
13
- @Override
14
- public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
15
- List<NativeModule> modules = new ArrayList<>();
16
- modules.add(new PapyrusNativeEngineModule(reactContext));
17
- return modules;
18
- }
19
-
20
- @Override
21
- public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
22
- return Collections.singletonList(new PapyrusPageViewManager());
23
- }
24
- }
1
+ package com.papyrus.engine;
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
+ import java.util.ArrayList;
9
+ import java.util.Collections;
10
+ import java.util.List;
11
+
12
+ public class PapyrusPackage implements ReactPackage {
13
+ @Override
14
+ public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
15
+ List<NativeModule> modules = new ArrayList<>();
16
+ modules.add(new PapyrusNativeEngineModule(reactContext));
17
+ return modules;
18
+ }
19
+
20
+ @Override
21
+ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
22
+ return Collections.singletonList(new PapyrusPageViewManager());
23
+ }
24
+ }