diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a9d3d4a..d77cfcb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,20 @@ ## Newest Release +### 2.2.2 - 15 Mar 2022 + +- Adds image support to `PSKDFKit.present()` on Android. (#33312) +- Adds a new **Save As** example to the Catalog example project. (#33376) +- Updates for PSPDFKit 11.3.0 for iOS. (#33485) +- Fixes React Native Annotation Processor API for Android. (#33189, #33302) + +## Previous Releases + ### 2.2.1 - 04 Mar 2022 - Updates for PSPDFKit 8.1.2 for Android. (#33315) - Updates for PSPDFKit 11.2.4 for iOS. (#33315) - Fixes React Native Annotation Processor Catalog example for Android.(#33189) -## Previous Releases - ### 2.2.0 - 14 Feb 2022 - This release requires you to update your Android project's `compileSdkVersion` to version 31. Please refer to [our migration guide](https://pspdfkit.com/guides/react-native/migration-guides/react-native-2-2-migration-guide) for this release. diff --git a/android/src/main/java/com/pspdfkit/react/PSPDFKitModule.java b/android/src/main/java/com/pspdfkit/react/PSPDFKitModule.java index c0dba717..e32a48f7 100644 --- a/android/src/main/java/com/pspdfkit/react/PSPDFKitModule.java +++ b/android/src/main/java/com/pspdfkit/react/PSPDFKitModule.java @@ -62,6 +62,14 @@ public class PSPDFKitModule extends ReactContextBaseJavaModule implements Applic private static final int REQUEST_CODE_TO_INDEX = 16; private static final int MASKED_REQUEST_CODE_TO_REAL_CODE = 0xffff; + private static final String[] SUPPORTED_IMAGE_TYPES = new String[] { + ".jpg", + ".png", + ".jpeg", + ".tif", + ".tiff" + }; + @Nullable private Activity resumedActivity; @@ -103,6 +111,23 @@ public String getName() { @ReactMethod public void present(@NonNull String document, @NonNull ReadableMap configuration, @Nullable Promise promise) { + File documentFile = new File(document); + if(isPdf(documentFile)) { + lastPresentPromise = promise; + presentPdf(document, configuration, promise); + } else if(isImage(documentFile)) { + lastPresentPromise = promise; + presentImage(document, configuration, promise); + }else { + Throwable error = new Throwable("The document must be one of these file types: .pdf, .jpg, .png, .jpeg, .tif, .tiff"); + if (promise!=null){ + promise.reject(error); + } + } + } + + @ReactMethod + public void presentPdf(@NonNull String document, @NonNull ReadableMap configuration, @Nullable Promise promise) { if (getCurrentActivity() != null) { if (resumedActivity == null) { // We register an activity lifecycle callback so we can get notified of the current activity. @@ -118,7 +143,7 @@ public void present(@NonNull String document, @NonNull ReadableMap configuration PdfActivity.showDocument(getCurrentActivity(), Uri.parse(document), configurationAdapter.build()); } } - + @ReactMethod public void presentImage(@NonNull String imageDocument, @NonNull ReadableMap configuration, @Nullable Promise promise) { if (getCurrentActivity() != null) { @@ -202,7 +227,12 @@ public void processAnnotations(@NonNull final String processingMode, @NonNull final String sourceDocumentPath, @NonNull final String targetDocumentPath, @NonNull final Promise promise) { - PdfDocumentLoader.openDocumentAsync(getReactApplicationContext(), Uri.parse(sourceDocumentPath)) + + // This is an edge case where file scheme is missing. + String documentPath = Uri.parse(sourceDocumentPath).getScheme() == null + ? FILE_SCHEME + sourceDocumentPath : sourceDocumentPath; + + PdfDocumentLoader.openDocumentAsync(getReactApplicationContext(), Uri.parse(documentPath)) .flatMapCompletable(document -> { PdfProcessorTask task = PdfProcessorTask.fromDocument(document); final EnumSet types = ConversionHelpers.getAnnotationTypeFromString(annotationType); @@ -344,4 +374,17 @@ public void run() { public void onNewIntent(Intent intent) { // Not required right now. } + + private boolean isPdf(File file) { + return file.getName().toLowerCase().endsWith(".pdf"); + } + + private boolean isImage(File file) { + for (String extension: SUPPORTED_IMAGE_TYPES) { + if (file.getName().toLowerCase().endsWith(extension)) { + return true; + } + } + return false; + } } diff --git a/android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java b/android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java index 5cb13ae7..9912373d 100644 --- a/android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java +++ b/android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java @@ -92,21 +92,14 @@ public void onDropViewInstance(PdfView view) { @Nullable @Override public Map getCommandsMap() { - Map commandMap = MapBuilder.of( - "enterAnnotationCreationMode", - COMMAND_ENTER_ANNOTATION_CREATION_MODE, - "exitCurrentlyActiveMode", - COMMAND_EXIT_CURRENTLY_ACTIVE_MODE, - "saveCurrentDocument", - COMMAND_SAVE_CURRENT_DOCUMENT, - "getAnnotations", - COMMAND_GET_ANNOTATIONS, - "addAnnotation", - COMMAND_ADD_ANNOTATION, - "getAllUnsavedAnnotations", - COMMAND_GET_ALL_UNSAVED_ANNOTATIONS, - "addAnnotations", - COMMAND_ADD_ANNOTATIONS); + Map commandMap = MapBuilder.of(); + commandMap.put("enterAnnotationCreationMode", COMMAND_ENTER_ANNOTATION_CREATION_MODE); + commandMap.put("exitCurrentlyActiveMode", COMMAND_EXIT_CURRENTLY_ACTIVE_MODE); + commandMap.put("saveCurrentDocument", COMMAND_SAVE_CURRENT_DOCUMENT); + commandMap.put("getAnnotations", COMMAND_GET_ANNOTATIONS); + commandMap.put("addAnnotation", COMMAND_ADD_ANNOTATION); + commandMap.put("getAllUnsavedAnnotations", COMMAND_GET_ALL_UNSAVED_ANNOTATIONS); + commandMap.put("addAnnotations", COMMAND_ADD_ANNOTATIONS); commandMap.put("getFormFieldValue", COMMAND_GET_FORM_FIELD_VALUE); commandMap.put("setFormFieldValue", COMMAND_SET_FORM_FIELD_VALUE); commandMap.put("removeAnnotation", COMMAND_REMOVE_ANNOTATION); diff --git a/index.js b/index.js index edf5e371..9b545a6e 100644 --- a/index.js +++ b/index.js @@ -101,7 +101,6 @@ class PSPDFKitView extends React.Component { this._requestMap.delete(requestId); }; - /** * Enters the annotation creation mode, showing the annotation creation toolbar. */ @@ -508,22 +507,21 @@ class PSPDFKitView extends React.Component { /** * Removes the currently displayed Android Native PdfUiFragment. - * + * * This function should only be used as a workaround for a bug in `react-native-screen` that causes a crash when - * `navigation.goBack()` is called or a hardware back button is used to navigate back on Android. Calling this + * `navigation.goBack()` is called or a hardware back button is used to navigate back on Android. Calling this * function will prevent the crash by removing the fragment from the `PdfView` before the navigation takes place. - * + * * Note: this function is available for Android only, it will have no effect on iOS. */ - destroyView = function () { + destroyView = function () { if (Platform.OS === "android") { UIManager.dispatchViewManagerCommand( findNodeHandle(this.refs.pdfView), - this._getViewManagerConfig("RCTPSPDFKitView").Commands - .removeFragment, + this._getViewManagerConfig("RCTPSPDFKitView").Commands.removeFragment, [] ); - } + } }; _getViewManagerConfig = (viewManagerName) => { diff --git a/package.json b/package.json index 12cb5ea1..aa9deda5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-pspdfkit", - "version": "2.2.1", + "version": "2.2.2", "description": "React Native PDF Library by PSPDFKit", "keywords": [ "react native", diff --git a/samples/Catalog/.watchmanconfig b/samples/Catalog/.watchmanconfig index 9e26dfee..0967ef42 100644 --- a/samples/Catalog/.watchmanconfig +++ b/samples/Catalog/.watchmanconfig @@ -1 +1 @@ -{} \ No newline at end of file +{} diff --git a/samples/Catalog/Catalog.js b/samples/Catalog/Catalog.js index 33b2b8d7..3c3af8ab 100644 --- a/samples/Catalog/Catalog.js +++ b/samples/Catalog/Catalog.js @@ -8,25 +8,39 @@ // Imports import React, {Component} from 'react'; -import {FlatList, Image, processColor, StyleSheet, Text, TouchableHighlight, View} from 'react-native'; +import { + FlatList, + Image, + processColor, + StyleSheet, + Text, + TouchableHighlight, + View, +} from 'react-native'; import {createStackNavigator} from 'react-navigation-stack'; import {createAppContainer} from 'react-navigation'; -import {exampleDocumentName, exampleDocumentPath, pspdfkitColor, tiffImagePath} from "./configuration/Constants"; -import {extractFromAssetsIfMissing} from "./helpers/FileSystemHelpers"; -import {PSPDFKitViewComponent} from "./examples/PSPDFKitViewComponent"; -import {OpenImageDocument} from "./examples/OpenImageDocument"; -import {ManualSave} from "./examples/ManualSave"; -import {EventListeners} from "./examples/EventListeners"; -import {StateChange} from "./examples/StateChange"; -import {PSPDFKit} from "./helpers/PSPDFKit"; -import {AnnotationProcessing} from "./examples/AnnotationProcessing"; -import {ProgrammaticAnnotations} from "./examples/ProgrammaticAnnotations"; -import {ProgrammaticFormFilling} from "./examples/ProgrammaticFormFilling"; -import {SplitPDF} from "./examples/SplitPDF"; -import {ToolbarCustomization} from "./examples/ToolbarCustomization"; -import {HiddenToolbar} from "./examples/HiddenToolbar"; -import {CustomFontPicker} from "./examples/CustomFontPicker"; +import { + exampleDocumentName, + exampleDocumentPath, + pspdfkitColor, + tiffImagePath, +} from './configuration/Constants'; +import {extractFromAssetsIfMissing} from './helpers/FileSystemHelpers'; +import {PSPDFKitViewComponent} from './examples/PSPDFKitViewComponent'; +import {OpenImageDocument} from './examples/OpenImageDocument'; +import {SaveAs} from './examples/SaveAs'; +import {ManualSave} from './examples/ManualSave'; +import {EventListeners} from './examples/EventListeners'; +import {StateChange} from './examples/StateChange'; +import {PSPDFKit} from './helpers/PSPDFKit'; +import {AnnotationProcessing} from './examples/AnnotationProcessing'; +import {ProgrammaticAnnotations} from './examples/ProgrammaticAnnotations'; +import {ProgrammaticFormFilling} from './examples/ProgrammaticFormFilling'; +import {SplitPDF} from './examples/SplitPDF'; +import {ToolbarCustomization} from './examples/ToolbarCustomization'; +import {HiddenToolbar} from './examples/HiddenToolbar'; +import {CustomFontPicker} from './examples/CustomFontPicker'; const fileSystem = require('react-native-fs'); @@ -95,6 +109,16 @@ const examples = [ }, { key: 'item4', + name: 'Save As', + description: 'Save changes to the PDF in a separate file', + action: component => { + extractFromAssetsIfMissing(exampleDocumentName, function () { + component.props.navigation.push('SaveAs'); + }); + }, + }, + { + key: 'item5', name: 'Event Listeners', description: 'Show how to use the listeners exposed by the PSPDFKitView component.', @@ -103,7 +127,7 @@ const examples = [ }, }, { - key: 'item5', + key: 'item6', name: 'Changing the State', description: 'Add a toolbar at the bottom with buttons to toggle the annotation toolbar, and to programmatically change pages.', @@ -111,8 +135,8 @@ const examples = [ component.props.navigation.push('StateChange'); }, }, - { - key: 'item6', + { + key: 'item7', name: 'Annotation Processing', description: 'Show how to embed, flatten, remove, and print annotations; then present the newly processed document.', @@ -123,7 +147,7 @@ const examples = [ }, }, { - key: 'item7', + key: 'item8', name: 'Programmatic Annotations', description: 'Show how to get and add new annotations using Instant JSON.', action: component => { @@ -131,7 +155,7 @@ const examples = [ }, }, { - key: 'item8', + key: 'item9', name: 'Programmatic Form Filling', description: 'Show how to get the value of a form element and how to programmatically fill forms.', @@ -140,7 +164,7 @@ const examples = [ }, }, Platform.OS === 'ios' && { - key: 'item9', + key: 'item10', name: 'Split PDF', description: 'Show two PDFs side by side by using multiple PSPDFKitView components.', @@ -149,7 +173,7 @@ const examples = [ }, }, Platform.OS === 'ios' && { - key: 'item10', + key: 'item11', name: 'Customize the Toolbar', description: 'Show how to customize buttons in the toolbar.', action: component => { @@ -157,7 +181,7 @@ const examples = [ }, }, { - key: 'item11', + key: 'item12', name: 'Hidden Toolbar', description: 'Hide the main toolbar while keeping the thumbnail bar visible.', @@ -166,7 +190,7 @@ const examples = [ }, }, { - key: 'item12', + key: 'item13', name: 'Custom Font Picker', description: 'Show how to customize the font picker for free text annotations.', @@ -176,7 +200,7 @@ const examples = [ }, /// Present examples. { - key: 'item13', + key: 'item14', name: 'Open a Document Using the Native Module API', description: 'Open a document using the Native Module API by passing its path.', @@ -193,7 +217,7 @@ const examples = [ }, }, { - key: 'item14', + key: 'item15', name: 'Customize Document Configuration', description: 'Customize various aspects of the document by passing a configuration dictionary.', @@ -202,18 +226,13 @@ const examples = [ }, }, { - key: 'item15', + key: 'item16', name: 'Open an Image Document Using the Native Module API', description: 'Open an image document using the Native Module API. Supported filetypes are PNG, JPEG and TIFF.', action: () => { // PSPDFKit can open PNG, JPEG and TIFF image files directly. - if (Platform.OS === 'ios') { - PSPDFKit.present(tiffImagePath, tiffImageConfiguration); - } - if (Platform.OS === 'android') { - PSPDFKit.presentImage(tiffImagePath, tiffImageConfiguration); - } + PSPDFKit.present(tiffImagePath, tiffImageConfiguration); }, }, ]; @@ -266,8 +285,7 @@ class Catalog extends Component { item.action(this); }} style={styles.row} - underlayColor={pspdfkitColor} - > + underlayColor={pspdfkitColor}> {item.name} {item.description} @@ -292,6 +310,9 @@ export default createAppContainer( ManualSave: { screen: ManualSave, }, + SaveAs: { + screen: SaveAs, + }, EventListeners: { screen: EventListeners, }, @@ -366,4 +387,3 @@ var styles = StyleSheet.create({ padding: 10, }, }); - diff --git a/samples/Catalog/configuration/Constants.js b/samples/Catalog/configuration/Constants.js index 7163d6b6..f959983a 100644 --- a/samples/Catalog/configuration/Constants.js +++ b/samples/Catalog/configuration/Constants.js @@ -24,6 +24,4 @@ export const tiffImagePath = export const pspdfkitColor = '#267AD4'; export const writableDocumentPath = - Platform.OS === 'ios' - ? fileSystem.DocumentDirectoryPath + '/' + exampleDocumentName - : 'file://' + fileSystem.DocumentDirectoryPath + '/' + exampleDocumentName; + fileSystem.DocumentDirectoryPath + '/' + exampleDocumentName; diff --git a/samples/Catalog/examples/AnnotationProcessing.js b/samples/Catalog/examples/AnnotationProcessing.js index 9c0085b6..b38e19a3 100644 --- a/samples/Catalog/examples/AnnotationProcessing.js +++ b/samples/Catalog/examples/AnnotationProcessing.js @@ -1,10 +1,7 @@ import {BaseExampleAutoHidingHeaderComponent} from '../helpers/BaseExampleAutoHidingHeaderComponent'; import {Button, processColor, View} from 'react-native'; import PSPDFKitView from 'react-native-pspdfkit'; -import { - pspdfkitColor, - writableDocumentPath, -} from '../configuration/Constants'; +import {pspdfkitColor, writableDocumentPath} from '../configuration/Constants'; import fileSystem from 'react-native-fs'; import {PSPDFKit} from '../helpers/PSPDFKit'; import React from 'react'; @@ -26,13 +23,15 @@ export class AnnotationProcessing extends BaseExampleAutoHidingHeaderComponent { style={{ flexDirection: 'column', alignItems: 'center', - }}> + }} + > + }} + >