Browse Source

compdfkit(rn) - 优化导入文档接口示例, 新增注释列表、表单列表示例

liuxiaolong 1 day ago
parent
commit
5772f9fbc8

+ 24 - 27
android/src/main/java/com/compdfkitpdf/reactnative/viewmanager/CPDFViewManager.java

@@ -105,6 +105,7 @@ public class CPDFViewManager extends ViewGroupManager<CPDFView> {
     Activity currentActivity = themedReactContext.getCurrentActivity();
     if (currentActivity instanceof FragmentActivity fragmentActivity) {
       CPDFView pdfView = new CPDFView(fragmentActivity);
+      pdfView.setId(View.generateViewId());
       pdfView.setup(themedReactContext, fragmentActivity.getSupportFragmentManager());
       pdfView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
       return pdfView;
@@ -737,46 +738,53 @@ public class CPDFViewManager extends ViewGroupManager<CPDFView> {
     CPDFView pdfView = mDocumentViews.get(tag);
     CPDFReaderView readerView = pdfView.getCPDFReaderView();
     CPDFDocument document = readerView.getPDFDocument();
-    if (!TextUtils.isEmpty(document.getAbsolutePath())){
+    if (!TextUtils.isEmpty(document.getAbsolutePath())) {
       return document.getAbsolutePath();
     }
     return document.getUri().toString();
   }
 
-  public WritableArray getAnnotations(int tag, int pageIndex){
+  public WritableArray getAnnotations(int tag, int pageIndex) {
     CPDFView pdfView = mDocumentViews.get(tag);
     CPDFPageUtil rcpdfPage = pdfView.getCPDFPageUtil();
     return rcpdfPage.getAnnotations(pageIndex);
   }
 
-  public WritableArray getForms(int tag, int pageIndex){
+  public WritableArray getForms(int tag, int pageIndex) {
     CPDFView pdfView = mDocumentViews.get(tag);
     CPDFPageUtil rcpdfPage = pdfView.getCPDFPageUtil();
     return rcpdfPage.getWidgets(pageIndex);
   }
 
-  public void setTextWidgetText(int tag, int pageIndex, String uuid, String text){
+  public void setTextWidgetText(int tag, int pageIndex, String uuid, String text) {
     CPDFView pdfView = mDocumentViews.get(tag);
     CPDFPageUtil rcpdfPage = pdfView.getCPDFPageUtil();
     rcpdfPage.setTextWidgetText(pageIndex, uuid, text);
   }
 
-  public void updateAp(int tag, int pageIndex, String uuid){
+  public void updateAp(int tag, int pageIndex, String uuid) {
     CPDFView pdfView = mDocumentViews.get(tag);
     CPDFPageUtil rcpdfPage = pdfView.getCPDFPageUtil();
-    rcpdfPage.updateAp(pageIndex, uuid);
     CPDFPageView pageView = (CPDFPageView) pdfView.getCPDFReaderView().getChild(pageIndex);
-    if (pageView != null) {
-      CPDFAnnotation annotation = rcpdfPage.getAnnotation(pageIndex, uuid);
-      CPDFBaseAnnotImpl impl = pageView.getAnnotImpl(annotation);
-      if (impl != null) {
-        impl.onAnnotAttrChange();
-      }
-      pageView.invalidate();
+    if (pageView == null) {
+      return;
+    }
+    CPDFAnnotation annotation = rcpdfPage.getAnnotation(pageIndex, uuid);
+    CPDFBaseAnnotImpl impl = pageView.getAnnotImpl(annotation);
+    if (impl == null) {
+      rcpdfPage.updateAp(pageIndex, uuid);
+      return;
+    }
+    if (impl instanceof CPDFSignatureWidgetImpl) {
+      ((CPDFSignatureWidgetImpl) impl).refresh();
+    } else {
+      rcpdfPage.updateAp(pageIndex, uuid);
+      impl.onAnnotAttrChange();
     }
+    pageView.invalidate();
   }
 
-  public void setWidgetIsChecked(int tag, int pageIndex, String uuid, boolean checked){
+  public void setWidgetIsChecked(int tag, int pageIndex, String uuid, boolean checked) {
     CPDFView pdfView = mDocumentViews.get(tag);
     CPDFPageUtil rcpdfPage = pdfView.getCPDFPageUtil();
     rcpdfPage.setChecked(pageIndex, uuid, checked);
@@ -784,18 +792,7 @@ public class CPDFViewManager extends ViewGroupManager<CPDFView> {
 
   public boolean addWidgetImageSignature(int tag, int pageIndex, String uuid, String imagePath) {
     CPDFView cpdfView = mDocumentViews.get(tag);
-    boolean result =  cpdfView.getCPDFPageUtil().addWidgetImageSignature(pageIndex, uuid, imagePath);
-    if (result){
-      CPDFPageView pageView = (CPDFPageView) cpdfView.getCPDFReaderView().getChild(pageIndex);
-      if (pageView != null) {
-        CPDFAnnotation annotation = cpdfView.getCPDFPageUtil().getAnnotation(pageIndex, uuid);
-        CPDFBaseAnnotImpl impl = pageView.getAnnotImpl(annotation);
-        if (impl != null && impl instanceof CPDFSignatureWidgetImpl) {
-          ((CPDFSignatureWidgetImpl) impl).refresh();
-        }
-        pageView.invalidate();
-      }
-    }
-    return result;
+    return cpdfView.getCPDFPageUtil().addWidgetImageSignature(pageIndex, uuid, imagePath);
   }
+
 }

+ 8 - 2
example/ios/CompdfkitPdfExample.xcodeproj/project.pbxproj

@@ -647,7 +647,10 @@
 					"-DFOLLY_CFG_NO_COROUTINES=1",
 					"-DFOLLY_HAVE_CLOCK_GETTIME=1",
 				);
-				OTHER_LDFLAGS = "$(inherited)  ";
+				OTHER_LDFLAGS = (
+					"$(inherited)",
+					" ",
+				);
 				REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
 				SDKROOT = iphoneos;
 				USE_HERMES = true;
@@ -720,7 +723,10 @@
 					"-DFOLLY_CFG_NO_COROUTINES=1",
 					"-DFOLLY_HAVE_CLOCK_GETTIME=1",
 				);
-				OTHER_LDFLAGS = "$(inherited)  ";
+				OTHER_LDFLAGS = (
+					"$(inherited)",
+					" ",
+				);
 				REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
 				SDKROOT = iphoneos;
 				USE_HERMES = true;

+ 17 - 7
example/package-lock.json

@@ -1,19 +1,20 @@
 {
   "name": "@compdfkit_pdf_sdk/react_native-example",
-  "version": "2.2.1",
+  "version": "2.3.0-beta.1",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "@compdfkit_pdf_sdk/react_native-example",
-      "version": "2.2.1",
+      "version": "2.3.0-beta.1",
       "dependencies": {
         "@react-navigation/native": "^6.1.17",
         "@react-navigation/native-stack": "^6.10.0",
         "react": "18.2.0",
         "react-native": "0.74.0",
-        "react-native-document-picker": "^9.1.0",
+        "react-native-document-picker": "^9.3.1",
         "react-native-fs": "^2.20.0",
+        "react-native-image-picker": "^8.2.0",
         "react-native-popup-menu": "^0.16.1",
         "react-native-safe-area-context": "^4.10.7",
         "react-native-screens": "^3.32.0",
@@ -7056,10 +7057,10 @@
       }
     },
     "node_modules/react-native-document-picker": {
-      "version": "9.3.0",
-      "resolved": "https://registry.npmmirror.com/react-native-document-picker/-/react-native-document-picker-9.3.0.tgz",
-      "integrity": "sha512-X/j0xKn8cObckpHTNwE/hW9WzBiP6oKx820FYu1Nat43QnnHmmT6uozFgAUDcJfxmZGcEdLlbv0lNhnyRXJyyA==",
-      "license": "MIT",
+      "version": "9.3.1",
+      "resolved": "https://registry.npmjs.org/react-native-document-picker/-/react-native-document-picker-9.3.1.tgz",
+      "integrity": "sha512-Vcofv9wfB0j67zawFjfq9WQPMMzXxOZL9kBmvWDpjVuEcVK73ndRmlXHlkeFl5ZHVsv4Zb6oZYhqm9u5omJOPA==",
+      "deprecated": "the package was renamed, follow migration instructions at https://shorturl.at/QYT4t",
       "dependencies": {
         "invariant": "^2.2.4"
       },
@@ -7092,6 +7093,15 @@
         }
       }
     },
+    "node_modules/react-native-image-picker": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-8.2.0.tgz",
+      "integrity": "sha512-jIGllQJuJIn0YKss/JEeb0Kos1HSsnIpU+i3bYxR27sOxSyDZQyP9dKR22olssQPlfH+rGNR/Jc6xKRkhm48vw==",
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
     "node_modules/react-native-popup-menu": {
       "version": "0.16.1",
       "resolved": "https://registry.npmjs.org/react-native-popup-menu/-/react-native-popup-menu-0.16.1.tgz",

+ 1 - 1
example/package.json

@@ -15,7 +15,7 @@
     "@react-navigation/native-stack": "^6.10.0",
     "react": "18.2.0",
     "react-native": "0.74.0",
-    "react-native-document-picker": "^9.1.0",
+    "react-native-document-picker": "^9.3.1",
     "react-native-fs": "^2.20.0",
     "react-native-image-picker": "^8.2.0",
     "react-native-popup-menu": "^0.16.1",

+ 36 - 20
example/src/CPDFAnnotationsExample.tsx

@@ -1,5 +1,5 @@
 /**
- * Copyright © 2014-2024 PDF Technologies, Inc. All Rights Reserved.
+ * Copyright © 2014-2025 PDF Technologies, Inc. All Rights Reserved.
  *
  * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
  * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
@@ -9,12 +9,13 @@
 
 import React, { useState, useRef } from 'react';
 import { Image, Platform, StyleSheet, Text, View } from 'react-native';
-import { CPDFReaderView, ComPDFKit, CPDFToolbarAction, CPDFDocument, CPDFPage, CPDFWidgetType, CPDFTextWidget, CPDFCheckboxWidget, CPDFRadiobuttonWidget, CPDFSignatureWidget } from '@compdfkit_pdf_sdk/react_native';
+import PDFReaderContext, { CPDFReaderView, ComPDFKit, CPDFToolbarAction, CPDFAnnotation } from '@compdfkit_pdf_sdk/react_native';
 import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
 import { HeaderBackButton } from '@react-navigation/elements';
 import { MenuProvider, Menu, MenuTrigger, MenuOptions, MenuOption } from 'react-native-popup-menu';
 import { SafeAreaView } from 'react-native-safe-area-context';
 import DocumentPicker from 'react-native-document-picker';
+import { CPDFAnnotationListScreen } from './screens/CPDFAnnotationListScreen';
 
 type RootStackParamList = {
     CPDFReaderViewExample: { document?: string };
@@ -33,6 +34,10 @@ const CPDFAnnotationsExampleScreen = () => {
 
     const route = useRoute<CPDFReaderViewExampleScreenRouteProp>();
 
+    const [annotationModalVisible, setAnnotationModalVisible] = useState(false);
+
+    const [annotationData, setAnnotationData] = useState<CPDFAnnotation[]>([]);
+
     const [samplePDF] = useState(
         route.params?.document || (Platform.OS === 'android'
             ? 'file:///android_asset/PDF_Document.pdf'
@@ -118,12 +123,17 @@ const CPDFAnnotationsExampleScreen = () => {
                 break;
             case 'Get Annotations':
                 const pageCount = await pdfReaderRef!.current!._pdfDocument.getPageCount();
+                let allAnnotations: CPDFAnnotation[] = [];
                 for (let i = 0; i < pageCount; i++) {
                     const page = pdfReaderRef?.current?._pdfDocument.pageAtIndex(i);
                     const annotations = await page?.getAnnotations();
-                    console.log(`ComPDFKitRN-annotations pageIndex ${i}:`);
+                    if (annotations) {
+                        allAnnotations = allAnnotations.concat(annotations);
+                    }
                     console.log(JSON.stringify(annotations, null, 2));
                 }
+                setAnnotationData(allAnnotations);
+                setAnnotationModalVisible(true);
                 break;
             default:
                 break;
@@ -158,23 +168,29 @@ const CPDFAnnotationsExampleScreen = () => {
     };
 
     return (
-        <MenuProvider>
-            <SafeAreaView style={{ flex: 1 }}>
-                <View style={{ flex: 1 }}>
-                    {renderToolbar()}
-                    <CPDFReaderView
-                        ref={pdfReaderRef}
-                        document={samplePDF}
-                        configuration={ComPDFKit.getDefaultConfig({
-                            toolbarConfig: {
-                                iosLeftBarAvailableActions: [
-                                    CPDFToolbarAction.THUMBNAIL
-                                ]
-                            }
-                        })} />
-                </View>
-            </SafeAreaView>
-        </MenuProvider>
+        <PDFReaderContext.Provider value={pdfReaderRef.current}>
+            <MenuProvider>
+                <SafeAreaView style={{ flex: 1 }}>
+                    <View style={{ flex: 1 }}>
+                        {renderToolbar()}
+                        <CPDFReaderView
+                            ref={pdfReaderRef}
+                            document={samplePDF}
+                            configuration={ComPDFKit.getDefaultConfig({
+                                toolbarConfig: {
+                                    iosLeftBarAvailableActions: [
+                                        CPDFToolbarAction.THUMBNAIL
+                                    ]
+                                }
+                            })} />
+                        <CPDFAnnotationListScreen
+                            visible={annotationModalVisible}
+                            annotations={annotationData}
+                            onClose={() => setAnnotationModalVisible(false)} />
+                    </View>
+                </SafeAreaView>
+            </MenuProvider>
+        </PDFReaderContext.Provider>
     );
 };
 

+ 38 - 40
example/src/CPDFPagesExample.tsx

@@ -9,13 +9,13 @@
 
 import React, { useState, useRef } from 'react';
 import { Image, Platform, StyleSheet, Text, View } from 'react-native';
-import { CPDFReaderView, ComPDFKit, CPDFToolbarAction, CPDFDocument } from '@compdfkit_pdf_sdk/react_native';
+import PDFReaderContext, { CPDFReaderView, ComPDFKit, CPDFToolbarAction } from '@compdfkit_pdf_sdk/react_native';
 import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
 import { HeaderBackButton } from '@react-navigation/elements';
 import { MenuProvider, Menu, MenuTrigger, MenuOptions, MenuOption } from 'react-native-popup-menu';
 import { SafeAreaView } from 'react-native-safe-area-context';
-import DocumentPicker from 'react-native-document-picker';
 import RNFS from 'react-native-fs';
+import { CPDFImportDocumentScreen } from './screens/CPDFImportDocumentScreen';
 
 type RootStackParamList = {
     CPDFReaderViewExample: { document?: string };
@@ -34,6 +34,8 @@ const CPDFPagesExampleScreen = () => {
 
     const route = useRoute<CPDFPagesExampleScreenRouteProp>();
 
+    const [importModalVisible, setImportModalVisible] = useState(false);
+
     const [samplePDF] = useState(
         route.params?.document || (Platform.OS === 'android'
             ? 'file:///android_asset/PDF_Document.pdf'
@@ -62,28 +64,11 @@ const CPDFPagesExampleScreen = () => {
                 handleSave();
                 break;
             case 'Import Document':
-                const pickerResult = DocumentPicker.pick({
-                    type: [DocumentPicker.types.pdf],
-                    copyTo: 'cachesDirectory'
-                });
-                pickerResult.then(async (res) => {
-                    const file = res[0];
-                    const path = file!!.fileCopyUri!!
-                    if (!path?.endsWith('pdf')) {
-                        console.log('ComPDFKitRN please select pdf format file');
-                        return;
-                    }
-                    const pages = [0];
-                    const insertPosition = 0;
-                    const importResult = await pdfReaderRef.current?._pdfDocument.importDocument(
-                        path,pages, insertPosition
-                    )
-                    console.log('ComPDFKitRN importDocument:', importResult);
-                })
+                setImportModalVisible(true);
                 break;
             case 'Split Document':
                 // const uri = await ComPDFKit.createUri('split_document_test.pdf', '', 'application/pdf')
-                
+
                 const appCacheDirectory = RNFS.CachesDirectoryPath;
                 const savePath = appCacheDirectory + '/split_document_test.pdf';
 
@@ -92,7 +77,7 @@ const CPDFPagesExampleScreen = () => {
                     savePath, pages
                 )
                 console.log('ComPDFKitRN splitDocumentPages:', splitResult);
-                if(splitResult){
+                if (splitResult) {
                     console.log('ComPDFKitRN splitDocumentPages: Split document saved at:', savePath);
                     await pdfReaderRef?.current?._pdfDocument.open(savePath);
                 }
@@ -111,7 +96,6 @@ const CPDFPagesExampleScreen = () => {
             <View style={styles.toolbar}>
                 <HeaderBackButton onPress={handleBack} />
                 <Text style={styles.toolbarTitle}>Pages Example</Text>
-
                 <Menu>
                     <MenuTrigger>
                         <Image source={require('../assets/more.png')} style={{ width: 24, height: 24, marginEnd: 8 }} />
@@ -130,23 +114,37 @@ const CPDFPagesExampleScreen = () => {
     };
 
     return (
-        <MenuProvider>
-            <SafeAreaView style={{ flex: 1 }}>
-                <View style={{ flex: 1 }}>
-                    {renderToolbar()}
-                    <CPDFReaderView
-                        ref={pdfReaderRef}
-                        document={samplePDF}
-                        configuration={ComPDFKit.getDefaultConfig({
-                            toolbarConfig: {
-                                iosLeftBarAvailableActions: [
-                                    CPDFToolbarAction.THUMBNAIL
-                                ]
-                            }
-                        })} />
-                </View>
-            </SafeAreaView>
-        </MenuProvider>
+        <PDFReaderContext.Provider value={pdfReaderRef.current}>
+            <MenuProvider>
+                <SafeAreaView style={{ flex: 1 }}>
+                    <View style={{ flex: 1 }}>
+                        {renderToolbar()}
+                        <CPDFReaderView
+                            ref={pdfReaderRef}
+                            document={samplePDF}
+                            configuration={ComPDFKit.getDefaultConfig({
+                                toolbarConfig: {
+                                    iosLeftBarAvailableActions: [
+                                        CPDFToolbarAction.THUMBNAIL
+                                    ]
+                                }
+                            })} />
+                        <CPDFImportDocumentScreen
+                            visible={importModalVisible}
+                            onClose={() => {
+                                setImportModalVisible(false);
+                            }}
+                            onImport={async (document, pageRange, insertPosition) => {
+                                setImportModalVisible(false);
+                                const importResult = await pdfReaderRef.current?._pdfDocument.importDocument(
+                                    document, pageRange, insertPosition
+                                )
+                                console.log('ComPDFKitRN importDocument:', importResult);
+                            }} />
+                    </View>
+                </SafeAreaView>
+            </MenuProvider>
+        </PDFReaderContext.Provider>
     );
 };
 

+ 7 - 5
example/src/CPDFReaderViewControllerExample.tsx

@@ -91,10 +91,12 @@ const CPDFReaderViewControllerExampleScreen = () => {
         'setMargins',
         'removeSignFileList',
         'setScale',
-        'setPageSpacing',
-        'setPageSameWidth',
-        'isPageInScreen',
-        'setFixedScroll',
+        ...(Platform.OS === 'android') ? [
+            'setPageSpacing',
+            'setPageSameWidth',
+            'setFixedScroll',
+            'isPageInScreen',
+        ] : [],
         'print'];
 
     const handleMenuItemPress = async (action: string) => {
@@ -114,7 +116,7 @@ const CPDFReaderViewControllerExampleScreen = () => {
 
                 // const androidUri = await ComPDFKit.createUri('save_as_test.pdf', '', 'application/pdf');
                 const success = await pdfReaderRef.current?._pdfDocument.saveAs(savePath, false, true);
-                if(success){
+                if (success) {
                     await pdfReaderRef.current?._pdfDocument.open(savePath, '');
                 }
                 console.log('ComPDFKitRN saveAs:', success);

+ 4 - 2
example/src/CPDFSecurityExample.tsx

@@ -9,7 +9,7 @@
 
 import React, { useState, useRef } from 'react';
 import { Image, Platform, StyleSheet, Text, View } from 'react-native';
-import { CPDFReaderView, ComPDFKit, CPDFToolbarAction, CPDFDocumentEncryptAlgo, CPDFDocument } from '@compdfkit_pdf_sdk/react_native';
+import { CPDFReaderView, ComPDFKit, CPDFToolbarAction, CPDFDocumentEncryptAlgo } from '@compdfkit_pdf_sdk/react_native';
 import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
 import { HeaderBackButton } from '@react-navigation/elements';
 import { MenuProvider, Menu, MenuTrigger, MenuOptions, MenuOption } from 'react-native-popup-menu';
@@ -72,8 +72,10 @@ const CPDFSecurityExampleScreen = () => {
                 .catch(error => {
                     console.log('ComPDFKit-RN flattenAllPages error:', error);
                 });
-                await pdfReaderRef.current?.reloadPages();
                 console.log('ComPDFKit-RN flattenAllPages:', flattenResult);
+                if(flattenResult){
+                    pdfReaderRef?.current?._pdfDocument?.open(savePath)
+                }
                 break;
             case 'Document Info':
                 console.log('ComPDFKit-RN fileName:', await document?.getFileName());

+ 89 - 184
example/src/CPDFWidgetsExample.tsx

@@ -8,15 +8,14 @@
  */
 
 import React, { useState, useRef } from 'react';
-import { Image, Modal, Platform, ScrollView, StyleSheet, Switch, Text, TextInput, TouchableOpacity, View } from 'react-native';
-import { CPDFReaderView, ComPDFKit, CPDFToolbarAction, CPDFWidgetType, CPDFTextWidget, CPDFRadiobuttonWidget, CPDFSignatureWidget, CPDFWidget } from '@compdfkit_pdf_sdk/react_native';
+import { Image, Modal, Platform, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
+import PDFReaderContext, { CPDFReaderView, ComPDFKit, CPDFToolbarAction, CPDFWidgetType, CPDFTextWidget, CPDFRadiobuttonWidget, CPDFSignatureWidget, CPDFWidget } from '@compdfkit_pdf_sdk/react_native';
 import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
 import { HeaderBackButton } from '@react-navigation/elements';
 import { MenuProvider, Menu, MenuTrigger, MenuOptions, MenuOption } from 'react-native-popup-menu';
 import { SafeAreaView } from 'react-native-safe-area-context';
 import DocumentPicker from 'react-native-document-picker';
-import { launchImageLibrary } from 'react-native-image-picker';
-
+import { CPDFWidgetListScreen } from './screens/CPDFWidgetListScreen';
 type RootStackParamList = {
     CPDFWidgetExample: { document?: string };
 };
@@ -91,16 +90,6 @@ const CPDFWidgetsExampleScreen = () => {
                 const exportWidgetsPath = await pdfReaderRef.current?._pdfDocument.exportWidgets();
                 console.log('ComPDFKitRN exportWidgets:', exportWidgetsPath)
                 break;
-
-            case 'Get Annotations':
-                const pageCount = await pdfReaderRef!.current!._pdfDocument.getPageCount();
-                for (let i = 0; i < pageCount; i++) {
-                    const page = pdfReaderRef?.current?._pdfDocument.pageAtIndex(i);
-                    const annotations = await page?.getAnnotations();
-                    console.log(`ComPDFKitRN-annotations pageIndex ${i}:`);
-                    console.log(JSON.stringify(annotations, null, 2));
-                }
-                break;
             case 'Get Widgets':
                 const pageCount1 = await pdfReaderRef!.current!._pdfDocument.getPageCount();
                 let allWidgets: CPDFWidget[] = [];
@@ -146,185 +135,101 @@ const CPDFWidgetsExampleScreen = () => {
         );
     };
 
-    const widgetItem = (index: number, widget: CPDFWidget) => {
-        return (
-            <TouchableOpacity key={index} onPress={async () => {
-                await pdfReaderRef?.current?.setDisplayPageIndex(widget.page);
-                setWidgetsModalVisible(false);
-            }}>
-                <View style={{ width: '100%' }}>
-                    <View style={{ flexDirection: 'row' }}>
-                        <Text style={styles.widgetItem}>Title: </Text>
-                        <Text style={styles.widgetBody}>{widget.title}</Text>
-                    </View>
-                    <View style={{ flexDirection: 'row' }}>
-                        <Text style={styles.widgetItem}>Type: </Text>
-                        <Text style={styles.widgetBody}>{widget.type.toUpperCase()}</Text>
-                    </View>
-                    <View style={{ flexDirection: 'row' }}>
-                        <Text style={styles.widgetItem}>PageIndex: </Text>
-                        <Text style={styles.widgetBody}>{widget.page}</Text>
-                    </View>
-
-                    {widget.type === CPDFWidgetType.TEXT_FIELD && (
-                        <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
-                            <Text style={styles.widgetBody}>{(widget as CPDFTextWidget).text}</Text>
-                            <TouchableOpacity style={{ paddingHorizontal: 16, paddingVertical:4}} onPress={async () => {
-                                setCurrentEditingWidgetIndex(index);
-                                setTextEditModalVisible(true);
-                            }}>
-                                <Text style={styles.closeButtonText}>Edit</Text>
-                            </TouchableOpacity>
-                        </View>
-                    )}
-                    {(widget.type === CPDFWidgetType.RADIO_BUTTON || widget.type == CPDFWidgetType.CHECKBOX) && (
-                        <View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}>
-                            <Text style={styles.widgetItem}>isChecked:</Text>
-                            <Switch
-                                thumbColor={(widget as CPDFRadiobuttonWidget).isChecked ? '#1460F3' : 'white'}
-                                trackColor={{ false: '#E0E0E0', true: '#1460F34D' }}
-                                value={(widget as CPDFRadiobuttonWidget).isChecked} onValueChange={async () => {
-                                    const updatedWidgetData = [...widgetData];
-
-                                    if ((widget as CPDFRadiobuttonWidget).type === CPDFWidgetType.RADIO_BUTTON || (widget as CPDFRadiobuttonWidget).type === CPDFWidgetType.CHECKBOX) {
-                                        const updatedWidget = widget as CPDFRadiobuttonWidget;
-                                        const newChecked = !updatedWidget.isChecked;
-                                        // change RadioButtonWidget or CPDFCheckboxWidget checked status;
-                                        await updatedWidget.setChecked(newChecked);
-                                        // update appearance
-                                        await updatedWidget.updateAp();
-
-                                        updatedWidgetData[index] = { ...widget, isChecked: newChecked };
-                                        setWidgetData(updatedWidgetData);
-                                    }
-                                }} />
-                        </View>
-                    )}
-                    {widget.type === CPDFWidgetType.SIGNATURES_FIELDS && (
-                        <View style={{ flexDirection: 'row', justifyContent: 'flex-end' }}>
-                            <TouchableOpacity style={{ paddingVertical:4}} onPress={async () => {
-                                const signatureWidget = widget as CPDFSignatureWidget;
-                                launchImageLibrary({
-                                    mediaType:'photo'
-                                }, async res => {
-                                    if( res.didCancel){
-                                        return false;
-                                    }
-                                    const path = res.assets?.[0]?.uri;
-                                    const signResult = await signatureWidget?.addImageSignature(path!);
-                                    if(signResult){
-                                        setWidgetsModalVisible(false);
-                                    }
-                                    return true;
-                                })
-                            }}>
-                                <Text style={styles.closeButtonText}>Signature</Text>
-                            </TouchableOpacity>
-                        </View>
-                    )}
-                    <View style={{ flex: 1, height: 1.5, backgroundColor: 'gray', opacity: 0.2, marginVertical: 5 }} />
-                </View>
-            </TouchableOpacity>
-        );
-    }
-
     return (
-        <MenuProvider>
-            <SafeAreaView style={{ flex: 1 }}>
-                <View style={{ flex: 1 }}>
-                    {renderToolbar()}
-                    <CPDFReaderView
-                        ref={pdfReaderRef}
-                        document={samplePDF}
-                        configuration={ComPDFKit.getDefaultConfig({
-                            toolbarConfig: {
-                                iosLeftBarAvailableActions: [
-                                    CPDFToolbarAction.THUMBNAIL
-                                ]
-                            }
-                        })} />
-                </View>
-                <Modal visible={widgetsModalVisible} transparent={true} animationType="slide">
-                    <View style={styles.modalContainer}>
-                        <View style={styles.modalContent}>
-                            <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
-                                <Text style={styles.modalTitle}>Forms List</Text>
-                                <TouchableOpacity onPress={() => setWidgetsModalVisible(false)} style={styles.closeButton}>
-                                    <Text style={styles.closeButtonText}>Close</Text>
-                                </TouchableOpacity>
-                            </View>
-                            <ScrollView>
-                                {widgetData.map((widget, index) => (
-                                    widgetItem(index, widget)
-                                ))}
-                            </ScrollView>
-                        </View>
+        <PDFReaderContext.Provider value={pdfReaderRef.current}>
+            <MenuProvider>
+                <SafeAreaView style={{ flex: 1 }}>
+                    <View style={{ flex: 1 }}>
+                        {renderToolbar()}
+                        <CPDFReaderView
+                            ref={pdfReaderRef}
+                            document={samplePDF}
+                            configuration={ComPDFKit.getDefaultConfig({
+                                toolbarConfig: {
+                                    iosLeftBarAvailableActions: [
+                                        CPDFToolbarAction.THUMBNAIL
+                                    ]
+                                }
+                            })} />
                     </View>
-                </Modal>
-
-                <Modal visible={textEditModalVisible} transparent={true} animationType="fade">
-                    <View style={styles.editTextModalContainer}>
-                        <View style={styles.editTextModalContent}>
-                            <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
-                                <Text style={styles.modalTitle}>Edit Text</Text>
-                            </View>
-
-                            <TextInput
-                                style={styles.inputField}
-                                value={text}
-                                onChangeText={(newText) => setText(newText)}
-                                placeholder="Enter text here"
-                                multiline={true}
-                                numberOfLines={4}
-                            />
-
-                            <View style={styles.buttonContainer}>
-                                <TouchableOpacity onPress={() => {
-                                    setTextEditModalVisible(false);
-                                }} style={styles.button}>
-                                    <Text style={styles.buttonText}>Cancel</Text>
-                                </TouchableOpacity>
-                                <TouchableOpacity onPress={async () => {
-                                    if (currentEditingWidgetIndex !== null && currentEditingWidgetIndex !== undefined) {
-                                    const updatedWidgetData = [...widgetData];
-                                    const widget = updatedWidgetData[currentEditingWidgetIndex];
-
-                                    console.log(JSON.stringify(widget, null, 2));
-                                    if(widget === undefined) {
-                                        return;
-                                    }
-                                    if (widget.type === CPDFWidgetType.TEXT_FIELD) {
-                                        const textWidget = widget as CPDFTextWidget;
-
-                                        try {
-                                            // change textFields text
-                                            await textWidget.setText(text);
-                                            await textWidget.updateAp();
-
-                                            if (updatedWidgetData[currentEditingWidgetIndex]) {
-                                                (updatedWidgetData[currentEditingWidgetIndex] as CPDFTextWidget).text = text;
+                    <CPDFWidgetListScreen
+                        visible={widgetsModalVisible}
+                        widgets={widgetData}
+                        onClose={() => setWidgetsModalVisible(false)}
+                        onEditText={(index: number) => {
+                            console.log('CPDFWidgetListScreen onEditText:', index);
+                            setCurrentEditingWidgetIndex(index);
+                            setTextEditModalVisible(true);
+                        }}
+                    />
+                    <Modal visible={textEditModalVisible} transparent={true} animationType="fade">
+                        <View style={styles.editTextModalContainer}>
+                            <View style={styles.editTextModalContent}>
+                                <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
+                                    <Text style={styles.modalTitle}>Edit Text</Text>
+                                </View>
+
+                                <TextInput
+                                    style={styles.inputField}
+                                    value={text}
+                                    onChangeText={(newText) => setText(newText)}
+                                    placeholder="Enter text here"
+                                    multiline={true}
+                                    numberOfLines={4}
+                                    returnKeyType='done'
+                                    blurOnSubmit={true}
+
+                                />
+
+                                <View style={styles.buttonContainer}>
+                                    <TouchableOpacity onPress={() => {
+                                        setTextEditModalVisible(false);
+                                    }} style={styles.button}>
+                                        <Text style={styles.buttonText}>Cancel</Text>
+                                    </TouchableOpacity>
+                                    <TouchableOpacity onPress={async () => {
+                                        if (currentEditingWidgetIndex !== null && currentEditingWidgetIndex !== undefined) {
+                                            const updatedWidgetData = [...widgetData];
+                                            const widget = updatedWidgetData[currentEditingWidgetIndex];
+
+                                            console.log(JSON.stringify(widget, null, 2));
+                                            if (widget === undefined) {
+                                                return;
+                                            }
+                                            if (widget.type === CPDFWidgetType.TEXT_FIELD) {
+                                                const textWidget = widget as CPDFTextWidget;
+
+                                                try {
+                                                    console.log('ComPDFKitRN setText:', text);
+                                                    // -------------------->
+                                                    // change textFields text
+                                                    await textWidget.setText(text);
+                                                    await textWidget.updateAp();
+                                                    // <---------------------
+                                                    if (updatedWidgetData[currentEditingWidgetIndex]) {
+                                                        (updatedWidgetData[currentEditingWidgetIndex] as CPDFTextWidget).text = text;
+                                                    }
+                                                    setWidgetData(updatedWidgetData);
+                                                    setText('');
+                                                } catch (error) {
+                                                    console.error("Failed to update text widget:", error);
+                                                }
                                             }
-                                            setWidgetData(updatedWidgetData);
-                                        } catch (error) {
-                                            console.error("Failed to update text widget:", error);
+                                            setTextEditModalVisible(false);
                                         }
-                                    }
-                                    setTextEditModalVisible(false);
-                                }
-                                }} style={styles.button}>
-                                    <Text style={styles.buttonText}>Confirm</Text>
+                                    }} style={styles.button}>
+                                        <Text style={styles.buttonText}>Confirm</Text>
 
-                                </TouchableOpacity>
+                                    </TouchableOpacity>
+                                </View>
                             </View>
                         </View>
-                    </View>
-                </Modal>
+                    </Modal>
 
-            </SafeAreaView>
-        </MenuProvider>
+                </SafeAreaView>
+            </MenuProvider>
+        </PDFReaderContext.Provider>
     );
-
-
 };
 
 

+ 188 - 0
example/src/screens/CPDFAnnotationListScreen.tsx

@@ -0,0 +1,188 @@
+/**
+ * Copyright © 2014-2025 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
+import PDFReaderContext, { CPDFAnnotation, CPDFReaderView } from "@compdfkit_pdf_sdk/react_native";
+import { useContext, useEffect } from "react";
+import { FlatList, Modal, StyleSheet, Text, TouchableOpacity, TouchableWithoutFeedback, View } from "react-native";
+
+interface CPDFAnnotationListScreenProps {
+    visible: boolean;
+    annotations: CPDFAnnotation[];
+    onClose: () => void;
+}
+
+export const CPDFAnnotationListScreen: React.FC<CPDFAnnotationListScreenProps> = ({ visible, annotations, onClose }) => {
+
+    const pdfReader = useContext(PDFReaderContext) as CPDFReaderView | null;
+
+    useEffect(() => {
+
+    }, [visible, pdfReader])
+
+    const groupedAnnotations = annotations.reduce((acc, item) => {
+        if (!acc[item.page]) {
+            acc[item.page] = [];
+        }
+        acc[item.page].push(item);
+        return acc;
+    }, {} as Record<number, CPDFAnnotation[]>);
+    
+    const flattenedData: (CPDFAnnotation | { isTitle: true, page: number, total: number })[] = [];
+    
+    Object.entries(groupedAnnotations).forEach(([page, items]) => {
+        flattenedData.push({ isTitle: true, page: Number(page), total: items.length }); 
+        flattenedData.push(...items); 
+    });
+
+    const _item = (annotation: CPDFAnnotation, onPress: () => void) => {
+        return (
+            <TouchableOpacity onPress={async () => {
+                onPress();
+            }}>
+                <View style={{ width: '100%',paddingVertical:12 }}>
+                    <View style={{ flexDirection: 'row' }}>
+                        <Text style={styles.widgetItem}>Title: </Text>
+                        <Text style={styles.widgetBody}>{annotation.title}</Text>
+                    </View>
+                    <View style={{ flexDirection: 'row' }}>
+                        <Text style={styles.widgetItem}>Type: </Text>
+                        <Text style={styles.widgetBody}>{annotation.type.toUpperCase()}</Text>
+                    </View>
+                    {annotation.content != '' && (
+                        <Text style={styles.widgetBody1}>{annotation.content}</Text>
+                    )}
+                </View>
+            </TouchableOpacity>
+        );
+    }
+
+
+    return (
+        <Modal
+            animationType="slide"
+            transparent={true}
+            visible={visible}
+            onRequestClose={onClose}>
+            <TouchableWithoutFeedback onPress={onClose}>
+                <View style={styles.modalContainer}>
+                    <TouchableWithoutFeedback>
+                        <View style={styles.modalContent}>
+                            <Text style={styles.title}>Annotations</Text>
+                            <FlatList
+                                data={flattenedData}
+                                renderItem={({ item }) =>
+                                    'isTitle' in item ?
+                                        (
+                                            <View style={styles.pageTitleContainer} >
+                                                <Text style={styles.pageTitle}>Page {item.page + 1}</Text>
+                                                <Text style={{
+                                                            fontSize : 14,
+                                                            color : 'black',
+                                                            fontWeight : 'bold',
+                                                            marginEnd : 8
+                                                }}>{'isTitle' in item ? item.total : 0}</Text>
+                                            </View>
+                                        )
+                                        :
+                                    _item(
+                                        item as CPDFAnnotation,
+                                        async () => {
+                                            await pdfReader?.setDisplayPageIndex(item.page);
+                                            onClose();
+                                        }
+                                    )
+                                }
+                                keyExtractor={item => 'isTitle' in item ? `title-${item.page}` : (item as CPDFAnnotation).uuid}
+                            />
+                        </View>
+                    </TouchableWithoutFeedback>
+                </View>
+            </TouchableWithoutFeedback>
+        </Modal>
+    );
+
+
+}
+
+const styles = StyleSheet.create({
+    modalContainer: {
+        flex: 1,
+        justifyContent: 'flex-end',
+        backgroundColor: 'rgba(3, 3, 3, 0.2)',
+    },
+    container: {
+        height: '60%',
+        justifyContent: 'flex-end',
+        backgroundColor: 'rgba(0, 0, 0, 0.1)',
+    },
+    modalView: {
+        backgroundColor: 'white',
+        justifyContent: 'flex-start',
+        borderTopLeftRadius: 20,
+        borderTopRightRadius: 20,
+    },
+    modalContent: {
+        width: '100%',
+        maxHeight: '60%',
+        backgroundColor: 'white',
+        padding: 16,
+        borderTopLeftRadius: 10,
+        borderTopRightRadius: 10,
+    },
+    title: {
+        fontSize: 20,
+        fontWeight: 'bold',
+        marginTop: 8,
+        marginBottom: 16,
+        color: 'black',
+    },
+    item: {
+        height: 48,
+        marginStart: 16,
+        flexDirection: 'row',
+        alignItems: 'center',
+        justifyContent: 'space-between',
+        marginEnd: 16,
+    },
+    itemTextNormal: {
+        textAlignVertical: 'center',
+        fontSize: 14,
+        color: 'gray'
+    },
+    itemTextSelect: {
+        textAlignVertical: 'center',
+        color: 'black',
+        fontSize: 14
+    },
+    widgetItem: {
+        fontSize: 14,
+        fontWeight: '500',
+        color: 'black'
+    },
+    widgetBody: {
+        fontSize: 14,
+    },
+    widgetBody1: {
+        fontSize: 13,
+    },
+    pageTitleContainer: {
+        flexDirection: 'row',
+        alignItems: 'center',
+        justifyContent: 'space-between',
+        height:32,
+        backgroundColor: '#DDE9FF',
+        paddingLeft:4,
+        borderRadius: 4
+    },
+    pageTitle : {
+        fontSize : 14,
+        color : 'black',
+        fontWeight : 'bold',
+    }
+});

+ 38 - 12
example/src/screens/CPDFDisplaySettingsScreen.tsx

@@ -1,6 +1,15 @@
+/**
+ * Copyright © 2014-2025 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
 import PDFReaderContext, { CPDFDisplayMode, CPDFThemes } from "@compdfkit_pdf_sdk/react_native";
 import { useContext, useEffect, useState } from "react";
-import { Image, Modal, ScrollView, StyleSheet, Switch, Text, TouchableOpacity, TouchableWithoutFeedback, View } from "react-native";
+import { Image, Modal, Platform, ScrollView, StyleSheet, Switch, Text, TouchableOpacity, TouchableWithoutFeedback, View } from "react-native";
 import { CPDFReaderView } from "../../../lib/typescript/src";
 
 
@@ -66,7 +75,10 @@ export const CPDFDisplaySettingsScreen: React.FC<CPDFDisplaySettingsScreenProps>
     const renderScrollItem = () =>{
         return (
             <View>
-                <Text style={styles.subTitle}>Scroll</Text>
+                <View style={styles.subTitleView}>
+                    <Text style={styles.subTitle}>Scroll</Text>
+                </View>
+                
                 {_item('Vertical Scrolling', isVertical, () => {
                     pdfReader?.setVerticalMode(true);
                     setIsVertical(true);
@@ -82,7 +94,10 @@ export const CPDFDisplaySettingsScreen: React.FC<CPDFDisplaySettingsScreenProps>
     const renderDisplayMode = () => {
         return (
             <View>
-                <Text style={styles.subTitle}>Display Mode</Text>
+                <View style={styles.subTitleView}>
+                    <Text style={styles.subTitle}>Display Mode</Text>
+                </View>
+                
                 {_item('Single Page', displayMode == CPDFDisplayMode.SINGLE_PAGE, () => {
                     pdfReader?.setDoublePageMode(false)
                     setDisplayMode(CPDFDisplayMode.SINGLE_PAGE)
@@ -103,7 +118,7 @@ export const CPDFDisplaySettingsScreen: React.FC<CPDFDisplaySettingsScreenProps>
     const renderOtherSettings = () => {
         return (
             <View>
-                <View style={styles.subTitle} ></View>
+                <View style={styles.subTitleView} ></View>
                 {_switchItem('Highlight Links', isLinkHighlight, (value) => {
                     pdfReader?.setLinkHighlight(value);
                     setIsLinkHighlight(value);
@@ -120,7 +135,8 @@ export const CPDFDisplaySettingsScreen: React.FC<CPDFDisplaySettingsScreenProps>
                     pdfReader?.setCropMode(value);
                     setIsCrop(value);
                 })}
-                {_switchItem('Can Scale', isCanScale, (value) => {
+                
+                {Platform.OS === 'android' && _switchItem('Can Scale', isCanScale, (value) => {
                     pdfReader?.setCanScale(value);
                     setCanScale(value);
                 })}
@@ -131,7 +147,10 @@ export const CPDFDisplaySettingsScreen: React.FC<CPDFDisplaySettingsScreenProps>
     const renderThemes = () => {
         return (
             <View>
-                <Text style={styles.subTitle}>Themes</Text>
+                <View style={styles.subTitleView}>
+                    <Text style={styles.subTitle}>Themes</Text>
+                </View>
+                
                 {_item('Light', themes == CPDFThemes.LIGHT, () => {
                     pdfReader?.setReadBackgroundColor(CPDFThemes.LIGHT);
                     setThemes(CPDFThemes.LIGHT);
@@ -211,14 +230,14 @@ const styles = StyleSheet.create({
     container: {
         flex: 1,
         justifyContent: 'flex-end',
-        backgroundColor: 'rgba(0, 0, 0, 0.1)',
+        backgroundColor: 'rgba(0, 0, 0, 0.1)'
     },
     modalView: {
         backgroundColor: 'white',
         height: '80%',
         justifyContent: 'flex-start',
         borderTopLeftRadius: 20,
-        borderTopRightRadius: 20,
+        borderTopRightRadius: 20
     },
     title : {
         fontSize: 20,
@@ -228,15 +247,22 @@ const styles = StyleSheet.create({
         marginBottom : 16,
         color: 'black',
     },
-    subTitle : {
-        fontSize : 14,
+    subTitleView : {
+        justifyContent:'center',
         height: 32,
         marginHorizontal: 16,
+        lineHeight:32,
+        fontWeight : 'bold',
+        backgroundColor: '#DDE9FF',
+        paddingStart:8,
+        borderRadius: 4
+    },
+    subTitle : {
+        fontSize : 14,
         textAlignVertical: 'center',
+        alignContent:'center',
         color : 'black',
         fontWeight : 'bold',
-        backgroundColor: '#FAFCFF',
-        borderRadius: 4
     },
     item : {
         height : 48,

+ 305 - 0
example/src/screens/CPDFImportDocumentScreen.tsx

@@ -0,0 +1,305 @@
+/**
+ * Copyright © 2014-2025 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+import PDFReaderContext, { CPDFReaderView } from "@compdfkit_pdf_sdk/react_native";
+import { useContext, useEffect, useState } from "react";
+import { Image, Modal, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, TouchableWithoutFeedback, View } from "react-native";
+import DocumentPicker, { DocumentPickerResponse } from 'react-native-document-picker';
+
+interface CPDFImportDocumentScreenProps {
+    visible: boolean;
+    onClose: () => void;
+    onImport: (document: string, pageRange: number[], insertPosition: number) => void;
+}
+
+export const CPDFImportDocumentScreen: React.FC<CPDFImportDocumentScreenProps> = ({ visible, onClose, onImport }) => {
+
+    const pdfReader = useContext(PDFReaderContext) as CPDFReaderView | null;
+
+    const [document, setDocument] = useState<DocumentPickerResponse | undefined>();
+
+    const [text, setText] = useState('');
+
+    const [insertTo, setInsertTo] = useState('');
+
+    const [importAllPages, setImportAllPages] = useState(true);
+
+    const [insertOption, setInsertOption] = useState<'firstPage' | 'lastPage' | 'insertAfter'>('firstPage');
+
+
+    const handleTextChange = (newText: string) => {
+        const formattedText = newText
+            .replace(/[^0-9,]/g, '')
+            .replace(/,+/g, ',');
+
+        setText(formattedText);
+    };
+
+    const insertToHandleTextChange = (newText: string) => {
+        const formattedText = newText
+            .replace(/[^0-9,]/g, '')
+
+        setText(formattedText);
+    };
+
+    useEffect(() => {
+
+    }, [visible, pdfReader])
+
+    const radioItem = (select: boolean, title: string, onPress: () => void) => {
+        return (
+            <TouchableWithoutFeedback onPress={onPress}>
+                <View style={styles.option}>
+                    <Text style={select ? styles.titleMedium : styles.titleMediumUnSelect}>{title}</Text>
+                    {select && (
+                        <Image source={require('../../assets/right.png')} style={styles.icon} />
+                    )}
+                </View>
+            </TouchableWithoutFeedback>);
+    }
+
+    return (
+        <Modal
+            animationType="slide"
+            transparent={true}
+            visible={visible}
+            onRequestClose={onClose}>
+            <TouchableWithoutFeedback onPress={onClose}>
+                <View style={styles.container}>
+                    <TouchableWithoutFeedback>
+                        <View style={styles.modalView}>
+                            <View style={{
+                                flexDirection: 'row', justifyContent: 'space-between',
+                                alignItems: 'center', marginTop: 16
+                            }}>
+                                <Text style={styles.titleLarge}>Import Document</Text>
+                                <TouchableWithoutFeedback
+                                    disabled={document === null}
+                                    onPress={async () => {
+                                        
+                                        var pages: number[] = [];
+                                        if (!importAllPages) {
+                                            if (text === '') {
+                                                console.log('input page range is null')
+                                                return;
+                                            }
+                                            // This refers to the subscript position of the page number. 
+                                            // For example, the subscript of the first page is 0, so -1 is needed.
+                                            pages = text
+                                                .split(',')
+                                                .map(e => Number(e.trim()) -1) 
+                                                .filter(num => !isNaN(num));
+                                        }
+                                        var insertPosition = 0;
+                                        switch(insertOption){
+                                            case "firstPage":
+                                                insertPosition = 0;
+                                                break;
+                                            case "lastPage":
+                                                // To insert into the last page you can also set 'insertPosition' to -1
+                                                const pageCount = await pdfReader?._pdfDocument.getPageCount();
+                                                insertPosition = pageCount!;
+                                                break;
+                                            case "insertAfter":
+                                                if(insertTo === ''){
+                                                    console.log('insertTo page is empty----->')
+                                                    return;
+                                                }
+                                                insertPosition = (Number(insertTo) + 1);
+                                                break;
+                                        }
+                                        console.log('InsertDocumentInfo:', {
+                                            'document': document?.fileCopyUri,
+                                            'pages' : pages,
+                                            'insertPosition' : insertPosition
+                                        })
+                                        onImport(document?.fileCopyUri!, pages, insertPosition)
+
+                                    }}>
+                                    <Text style={{
+                                        fontSize: 14,
+                                        fontWeight: 'bold',
+                                        color: document != null ? 'black' : 'grey',
+                                        marginStart: 8,
+                                    }}>Done</Text>
+                                </TouchableWithoutFeedback>
+
+                            </View>
+
+                            <ScrollView keyboardShouldPersistTaps="handled">
+                                <View style={{ flexDirection: 'row', justifyContent: 'space-between', height: 56, alignItems: 'center', marginTop: 8 }}>
+                                    <Text style={styles.titleMedium}>File Name</Text>
+                                    <TouchableOpacity onPress={() => {
+                                        const pickerResult = DocumentPicker.pick({
+                                            type: [DocumentPicker.types.pdf],
+                                            copyTo: 'cachesDirectory'
+                                        });
+                                        pickerResult.then(async (res) => {
+                                            const file = res[0];
+                                            const path = file!!.fileCopyUri!!
+                                            if (!path?.endsWith('pdf')) {
+                                                console.log('ComPDFKitRN please select pdf format file');
+                                                return;
+                                            }
+                                            setDocument(file);
+
+
+                                            // const pages = [0];
+                                            // const insertPosition = 0;
+                                            // const importResult = await pdfReaderRef.current?._pdfDocument.importDocument(
+                                            //     path,pages, insertPosition
+                                            // )
+                                            // console.log('ComPDFKitRN importDocument:', importResult);
+                                        })
+                                    }}>
+                                        <View style={{ flexDirection: 'row', alignItems: 'center' }}>
+                                            <Text style={styles.subTextMedium}>{document != null ? document.name : 'Select File'}</Text>
+                                            <Image source={require('../../assets/arrow_right.png')} style={styles.icon} />
+                                        </View>
+                                    </TouchableOpacity>
+                                </View>
+                                <Text style={styles.header}>Page Range</Text>
+                                {/* Page Range Selection */}
+                                {radioItem(importAllPages, 'All Pages', () => {
+                                    setImportAllPages(true);
+                                })}
+                                {radioItem(!importAllPages, 'Custom Range', () => {
+                                    setImportAllPages(false);
+                                })}
+                                <View pointerEvents={importAllPages ? 'none' : 'auto'}>
+                                    <TextInput
+                                        style={[
+                                            styles.inputField,
+                                            importAllPages && styles.disabledInput
+                                        ]}
+                                        value={text}
+                                        onChangeText={handleTextChange}
+                                        placeholder="e.g. 1,2,3,4"
+                                        multiline={false}
+                                        numberOfLines={1}
+                                        returnKeyType='done'
+                                        blurOnSubmit={true}
+                                        editable={!importAllPages}
+                                        autoFocus={!importAllPages}
+                                    />
+                                </View>
+                                <Text style={styles.header}>Insert To</Text>
+                                {radioItem(insertOption === 'firstPage', 'First Page', () => {
+                                    setInsertOption('firstPage');
+                                })}
+                                {radioItem(insertOption === 'lastPage', 'Last Page', () => {
+                                    setInsertOption('lastPage')
+                                })}
+                                {radioItem(insertOption === 'insertAfter', 'Insert After Specified Page', () => {
+                                    setInsertOption('insertAfter')
+                                })}
+
+                                <View pointerEvents={insertOption != 'insertAfter' ? 'none' : 'auto'}>
+                                    <TextInput
+                                        style={[
+                                            styles.inputField,
+                                            !(insertOption === 'insertAfter') && styles.disabledInput
+                                        ]}
+                                        value={insertTo}
+                                        onChangeText={text => setInsertTo(text.replace(/[^0-9]/g, ''))}
+                                        placeholder="Please enter a page"
+                                        multiline={false}
+                                        numberOfLines={1}
+                                        keyboardType='numeric'
+                                        returnKeyType='done'
+                                        blurOnSubmit={true}
+                                        editable={insertOption === 'insertAfter'}
+                                        autoFocus={insertOption === 'insertAfter'}
+                                    />
+                                </View>
+                            </ScrollView>
+                        </View>
+                    </TouchableWithoutFeedback>
+                </View>
+            </TouchableWithoutFeedback>
+        </Modal>
+    );
+
+}
+
+
+const styles = StyleSheet.create({
+    container: {
+        flex: 1,
+        justifyContent: 'flex-end',
+        backgroundColor: 'rgba(0, 0, 0, 0.1)',
+    },
+    modalView: {
+        backgroundColor: 'white',
+        height: '80%',
+        justifyContent: 'flex-start',
+        borderTopLeftRadius: 20,
+        borderTopRightRadius: 20,
+        paddingHorizontal: 16
+    },
+    titleLarge: {
+        fontSize: 20,
+        fontWeight: 'bold',
+        color: 'black',
+    },
+    titleMedium: {
+        fontSize: 14,
+        fontWeight: 'bold',
+        color: 'black',
+        marginStart: 8
+    },
+    titleMediumUnSelect: {
+        fontSize: 14,
+        color: 'grey',
+        marginStart: 8
+    },
+    textMedium: {
+        fontSize: 14,
+        color: 'black'
+    },
+    subTextMedium: {
+        fontSize: 12,
+        color: 'grey'
+    },
+    icon: {
+        width: 24,
+        height: 24,
+        marginRight: 16
+    },
+    header: {
+        fontSize: 14,
+        height: 32,
+        lineHeight:32,
+        textAlignVertical: 'center',
+        color: 'black',
+        fontWeight: 'bold',
+        backgroundColor: '#DDE9FF',
+        paddingStart: 8,
+        borderRadius: 4
+    },
+    inputField: {
+        borderColor: 'gray',
+        borderWidth: 0.5,
+        borderRadius: 2,
+        paddingHorizontal: 8,
+        paddingVertical: 4,
+        marginBottom: 20,
+        marginTop: 8,
+        textAlignVertical: 'center',
+    },
+    disabledInput: {
+        backgroundColor: '#f2f2f2',
+        color: 'gray'
+    },
+    option: {
+        height: 48,
+        justifyContent: 'space-between',
+        alignItems: 'center',
+        flexDirection: 'row'
+    },
+});

+ 9 - 0
example/src/screens/CPDFPreviewModeListScreen.tsx

@@ -1,3 +1,12 @@
+/**
+ * Copyright © 2014-2025 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
 import PDFReaderContext, { CPDFReaderView, CPDFViewMode } from "@compdfkit_pdf_sdk/react_native";
 import { useContext, useState } from "react";
 import { FlatList, Image, Modal, StyleSheet, Text, TouchableOpacity, TouchableWithoutFeedback, View } from "react-native";

+ 300 - 0
example/src/screens/CPDFWidgetListScreen.tsx

@@ -0,0 +1,300 @@
+/**
+ * Copyright © 2014-2025 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
+import PDFReaderContext, { CPDFRadiobuttonWidget, CPDFReaderView, CPDFSignatureWidget, CPDFTextWidget, CPDFWidget, CPDFWidgetType } from "@compdfkit_pdf_sdk/react_native";
+import { useContext, useEffect, useState } from "react";
+import { FlatList, Modal, Platform, StyleSheet, Switch, Text, TouchableOpacity, TouchableWithoutFeedback, View } from "react-native";
+import { launchImageLibrary } from 'react-native-image-picker';
+
+interface CPDFWidgetListScreenProps {
+    visible: boolean;
+    widgets: CPDFWidget[];
+    onClose: () => void;
+    onEditText : (itemIndex : number) => void;
+}
+
+export const CPDFWidgetListScreen: React.FC<CPDFWidgetListScreenProps> = ({ visible, widgets, onClose, onEditText }) => {
+
+    const pdfReader = useContext(PDFReaderContext) as CPDFReaderView | null;
+
+    const [widgetData, setWidgetData] = useState<CPDFWidget[]>([]);
+
+
+    useEffect(() => {
+
+    }, [visible, pdfReader])
+
+    const groupedWidgets = widgets.reduce((acc, item) => {
+        if (!acc[item.page]) {
+            acc[item.page] = [];
+        }
+        acc[item.page].push(item);
+        return acc;
+    }, {} as Record<number, CPDFWidget[]>);
+
+    const flattenedData: (CPDFWidget | { isTitle: true, page: number, total: number })[] = [];
+
+    Object.entries(groupedWidgets).forEach(([page, items]) => {
+        flattenedData.push({ isTitle: true, page: Number(page), total: items.length });
+        flattenedData.push(...items);
+    });
+
+    const widgetItem = (widget: CPDFWidget, index: number, onPress: () => void, onEditText : (itemIndex : number) => void) => {
+        return (
+            <TouchableOpacity onPress={async () => {
+                onPress();
+            }}>
+                <View style={{ width: '100%' ,paddingVertical:12}}>
+                    <View style={{ flexDirection: 'row' }}>
+                        <Text style={styles.widgetItem}>Title: </Text>
+                        <Text style={styles.widgetBody}>{widget.title}</Text>
+                    </View>
+                    <View style={{ flexDirection: 'row' }}>
+                        <Text style={styles.widgetItem}>Type: </Text>
+                        <Text style={styles.widgetBody}>{widget.type.toUpperCase()}</Text>
+                    </View>
+
+                    {widget.type === CPDFWidgetType.TEXT_FIELD && (
+                        <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
+                            <Text style={styles.widgetBody}>{(widget as CPDFTextWidget).text}</Text>
+                            <TouchableOpacity style={{ paddingHorizontal: 16 }} onPress={async () => {
+                                if (Platform.OS === 'ios') {
+                                    onClose();
+                                }
+                                onEditText(index -1)
+                            }}>
+                                <Text style={styles.closeButtonText}>Edit</Text>
+                            </TouchableOpacity>
+                        </View>
+                    )}
+                    {(widget.type === CPDFWidgetType.RADIO_BUTTON || widget.type == CPDFWidgetType.CHECKBOX) && (
+                        <View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
+                            <Text style={styles.widgetItem}>Status:</Text>
+                            <Switch
+                                style={{transform:[{scale: 0.8}]}}
+                                thumbColor={(widget as CPDFRadiobuttonWidget).isChecked ? '#1460F3' : 'white'}
+                                trackColor={{ false: '#E0E0E0', true: '#1460F34D' }}
+                                value={(widget as CPDFRadiobuttonWidget).isChecked} onValueChange={async () => {
+                                    const updatedWidgetData = [...widgetData];
+
+                                    if ((widget as CPDFRadiobuttonWidget).type === CPDFWidgetType.RADIO_BUTTON || (widget as CPDFRadiobuttonWidget).type === CPDFWidgetType.CHECKBOX) {
+                                        const updatedWidget = widget as CPDFRadiobuttonWidget;
+                                        const newChecked = !updatedWidget.isChecked;
+
+                                        // ---------------------->
+                                        // change RadioButtonWidget or CPDFCheckboxWidget checked status;
+                                        await updatedWidget.setChecked(newChecked);
+                                        // update appearance
+                                        await updatedWidget.updateAp();
+                                        // <----------------------
+
+                                        updatedWidgetData[index] = { ...widget, isChecked: newChecked };
+                                        setWidgetData(updatedWidgetData);
+                                    }
+                                }} />
+                        </View>
+                    )}
+                    {widget.type === CPDFWidgetType.SIGNATURES_FIELDS && (
+                        <View style={{ flexDirection: 'row', justifyContent: 'flex-start' }}>
+                            <TouchableOpacity style={{ paddingVertical: 4 }} onPress={async () => {
+                                const signatureWidget = widget as CPDFSignatureWidget;
+                                launchImageLibrary({
+                                    mediaType: 'photo'
+                                }, async res => {
+                                    if (res.didCancel) {
+                                        return false;
+                                    }
+                                    const path = res.assets?.[0]?.uri;
+                                    const signResult = await signatureWidget?.addImageSignature(path!);
+                                    await signatureWidget?.updateAp();
+                                    if (signResult) {
+                                        onClose();
+                                    }
+                                    return true;
+                                })
+                            }}>
+                                <Text style={styles.closeButtonText}>Signature</Text>
+                            </TouchableOpacity>
+                        </View>
+                    )}
+                </View>
+            </TouchableOpacity>
+        );
+    }
+
+
+    return (
+        <Modal
+            animationType="slide"
+            transparent={true}
+            visible={visible}
+            onRequestClose={onClose}>
+            <TouchableWithoutFeedback onPress={onClose}>
+                <View style={styles.modalContainer}>
+                    <TouchableWithoutFeedback>
+                        <View style={styles.modalContent}>
+                            <Text style={styles.title}>Widgets</Text>
+                            <FlatList
+                                data={flattenedData}
+                                renderItem={({ item, index }) =>
+                                    'isTitle' in item ?
+                                        (
+                                            <View style={styles.pageTitleContainer} >
+                                                <Text style={styles.pageTitle}>Page {item.page + 1}</Text>
+                                                <Text style={{
+                                                    fontSize: 14,
+                                                    color: 'black',
+                                                    fontWeight: 'bold',
+                                                    marginEnd: 8
+                                                }}>{'isTitle' in item ? item.total : 0}</Text>
+                                            </View>
+                                        )
+                                        :
+                                        widgetItem(
+                                            item as CPDFWidget,
+                                            index,
+                                            async () => {
+                                                await pdfReader?.setDisplayPageIndex(item.page);
+                                                onClose();
+                                            },
+                                            onEditText
+                                        )
+                                }
+                                keyExtractor={item => 'isTitle' in item ? `title-${item.page}` : (item as CPDFWidget).uuid}
+                            />
+                        </View>
+                    </TouchableWithoutFeedback>
+                </View>
+            </TouchableWithoutFeedback>
+        </Modal>
+    );
+
+
+}
+
+const styles = StyleSheet.create({
+    modalContainer: {
+        flex: 1,
+        justifyContent: 'flex-end',
+        backgroundColor: 'rgba(3, 3, 3, 0.2)',
+    },
+    container: {
+        height: '60%',
+        justifyContent: 'flex-end',
+        backgroundColor: 'rgba(0, 0, 0, 0.1)',
+    },
+    modalView: {
+        backgroundColor: 'white',
+        justifyContent: 'flex-start',
+        borderTopLeftRadius: 20,
+        borderTopRightRadius: 20,
+    },
+    modalContent: {
+        width: '100%',
+        maxHeight: '60%',
+        backgroundColor: 'white',
+        padding: 16,
+        borderTopLeftRadius: 10,
+        borderTopRightRadius: 10,
+    },
+    title: {
+        fontSize: 20,
+        fontWeight: 'bold',
+        marginTop: 8,
+        marginBottom: 16,
+        color: 'black',
+    },
+    item: {
+        height: 48,
+        marginStart: 16,
+        flexDirection: 'row',
+        alignItems: 'center',
+        justifyContent: 'space-between',
+        marginEnd: 16,
+    },
+    itemTextNormal: {
+        textAlignVertical: 'center',
+        fontSize: 14,
+        color: 'gray'
+    },
+    itemTextSelect: {
+        textAlignVertical: 'center',
+        color: 'black',
+        fontSize: 14
+    },
+    widgetItem: {
+        fontSize: 14,
+        fontWeight: '500',
+        color: 'black'
+    },
+    widgetBody: {
+        fontSize: 14,
+    },
+    widgetBody1: {
+        fontSize: 13,
+    },
+    pageTitleContainer: {
+        flexDirection: 'row',
+        alignItems: 'center',
+        justifyContent: 'space-between',
+        height: 32,
+        backgroundColor: '#DDE9FF',
+        paddingLeft: 4,
+        borderRadius: 4
+    },
+    pageTitle: {
+        fontSize: 14,
+        color: 'black',
+        fontWeight: 'bold',
+    },
+    closeButton: {
+        paddingVertical: 4,
+        paddingHorizontal: 8,
+        marginEnd: 8,
+    },
+    closeButtonText: {
+        color: '#007BFF',
+        fontSize: 14,
+    },
+    editTextModalContainer: {
+        flex: 1,
+        justifyContent: 'center',
+        alignItems: 'center',
+        backgroundColor: 'rgba(3, 3, 3, 0.2)',
+    },
+    editTextModalContent: {
+        width: '80%',
+        backgroundColor: 'white',
+        padding: 16,
+        borderRadius: 10
+    },
+    inputField: {
+        height: 100,
+        borderColor: 'gray',
+        borderWidth: 1,
+        borderRadius: 5,
+        padding: 10,
+        marginBottom: 20,
+        textAlignVertical: 'top',
+    },
+    buttonContainer: {
+        flexDirection: 'row',
+        justifyContent: 'flex-end',
+    },
+    button: {
+        paddingVertical: 10,
+        paddingHorizontal: 20,
+        borderRadius: 5,
+        marginTop: 10,
+    },
+    buttonText: {
+        color: '#1460F3',
+        fontSize: 16,
+    },
+});

+ 9 - 0
example/src/screens/HomeScreen.tsx

@@ -1,3 +1,12 @@
+/**
+ * Copyright © 2014-2025 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
 import React, { Component } from "react";
 import {
   FlatList,

+ 9 - 2
example/src/screens/SettingScreen.tsx

@@ -1,8 +1,15 @@
+/**
+ * Copyright © 2014-2025 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
 import React, { Component } from "react";
 import {
-    FlatList,
     Image,
-    NativeModules,
     Text,
     StyleSheet,
     TouchableOpacity,