Skip to content

Commit

Permalink
Release 2.9.1
Browse files Browse the repository at this point in the history
  • Loading branch information
PSPDFKit committed Apr 12, 2024
1 parent c2affd4 commit dc6971a
Show file tree
Hide file tree
Showing 27 changed files with 433 additions and 98 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
## Newest Release

### 2.9.1 - 12 Apr 2024

- Adds the ability to import and export annotations from XFDF files. (J#HYB-293)
- Updates for PSPDFKit 2024.2.1 for Android.
- Fixes issue where password input UI for password-protected documents wasn't shown on Android. (J#HYB-285)

## Previous Releases

### 2.9.0 - 22 Mar 2024

- Adds new getConfiguration method to retrieve current PSPDFKitView configuration options. (J#HYB-192)
Expand All @@ -14,8 +22,6 @@
- Fixes signatureSavingStrategy configuration option to save signature if enabled. (J#HYB-210)
- Fixes `spreadFitting` configuration option behaviour on iOS. (J#HYB-222)

## Previous Releases

### 2.8.1 - 27 Feb 2024

- Updates for PSPDFKit 13.3.1 for iOS. (#43565)
Expand Down
2 changes: 2 additions & 0 deletions android/.settings/org.eclipse.buildship.core.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
connection.project.dir=../../../android
eclipse.preferences.version=1
10 changes: 2 additions & 8 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* Contains gradle configuration constants
*/
ext {
PSPDFKIT_VERSION = '2024.1.2'
PSPDFKIT_VERSION = '2024.2.1'
}

buildscript {
Expand Down Expand Up @@ -70,13 +70,7 @@ dependencies {
api("com.pspdfkit:pspdfkit:${PSPDFKIT_VERSION}") {
exclude group: 'com.google.auto.value', module: 'auto-value'
}

implementation "androidx.compose.material:material:1.5.4"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"
implementation "androidx.compose.foundation:foundation:1.5.4"
implementation "androidx.compose.ui:ui:1.5.4"


implementation "com.facebook.react:react-native:+"
implementation 'com.squareup.okhttp3:okhttp:4.9.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
Expand Down
60 changes: 0 additions & 60 deletions android/src/main/java/com/pspdfkit/react/PSPDFKitModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -267,66 +267,6 @@ public void processAnnotations(@NonNull final String processingMode,
});
}

@ReactMethod
public void setMeasurementScale(@Nullable final Scale scale) {
if (resumedActivity instanceof PdfActivity) {
final PdfActivity activity = (PdfActivity) resumedActivity;
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
PdfDocument document = activity.getDocument();
if (document != null && scale != null) {
document.setMeasurementScale(scale);
} else {
activity.getPdfFragment().addDocumentListener(new SimpleDocumentListener() {
@Override
public void onDocumentLoaded(@NonNull PdfDocument document) {
activity.getPdfFragment().removeDocumentListener(this);
}
});
}
}
});
} else {
onPdfActivityOpenedTask = new Runnable() {
@Override
public void run() {
setMeasurementScale(scale);
}
};
}
}
@ReactMethod
public void setMeasurementPrecision(@Nullable final MeasurementPrecision floatPrecision) {
if (resumedActivity instanceof PdfActivity) {
final PdfActivity activity = (PdfActivity) resumedActivity;
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
PdfDocument document = activity.getDocument();
MeasurementPrecision precision = floatPrecision;
if (document != null && precision != null) {
document.setMeasurementPrecision(precision);
} else {
activity.getPdfFragment().addDocumentListener(new SimpleDocumentListener() {
@Override
public void onDocumentLoaded(@NonNull PdfDocument document) {
activity.getPdfFragment().removeDocumentListener(this);
}
});
}
}
});
} else {
onPdfActivityOpenedTask = new Runnable() {
@Override
public void run() {
setMeasurementPrecision(floatPrecision);
}
};
}
}

private static PdfProcessorTask.AnnotationProcessingMode getProcessingModeFromString(@NonNull final String mode) {
if ("print".equalsIgnoreCase(mode)) {
return PdfProcessorTask.AnnotationProcessingMode.PRINT;
Expand Down
16 changes: 16 additions & 0 deletions android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public class ReactPdfViewManager extends ViewGroupManager<PdfView> {
public static final int COMMAND_SET_TOOLBAR = 19;
public static final int COMMAND_SET_MEASUREMENT_VALUE_CONFIGURATIONS = 21;
public static final int COMMAND_GET_MEASUREMENT_VALUE_CONFIGURATIONS = 22;
public static final int COMMAND_IMPORT_XFDF = 23;
public static final int COMMAND_EXPORT_XFDF = 24;

private final CompositeDisposable annotationDisposables = new CompositeDisposable();

Expand Down Expand Up @@ -123,6 +125,8 @@ public Map<String, Integer> getCommandsMap() {
commandMap.put("getMeasurementValueConfigurations", COMMAND_GET_MEASUREMENT_VALUE_CONFIGURATIONS);
commandMap.put("getConfiguration", COMMAND_GET_CONFIGURATION);
commandMap.put("setToolbar", COMMAND_SET_TOOLBAR);
commandMap.put("importXFDF", COMMAND_IMPORT_XFDF);
commandMap.put("exportXFDF", COMMAND_EXPORT_XFDF);
return commandMap;
}

Expand Down Expand Up @@ -421,6 +425,18 @@ public void accept(List<Annotation> annotations) {
setToolbar(root,args.getMap(0));
}
break;
case COMMAND_IMPORT_XFDF:
if (args != null && args.size() == 2) {
final int requestId = args.getInt(0);
root.importXFDF(requestId, args.getString(1));
}
break;
case COMMAND_EXPORT_XFDF:
if (args != null && args.size() == 2) {
final int requestId = args.getInt(0);
root.exportXFDF(requestId, args.getString(1));
}
break;
}
}

Expand Down
103 changes: 88 additions & 15 deletions android/src/main/java/com/pspdfkit/views/PdfView.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import com.facebook.react.uimanager.events.EventDispatcher;
import com.pspdfkit.PSPDFKit;
import com.pspdfkit.annotations.Annotation;
import com.pspdfkit.annotations.AnnotationProvider;
import com.pspdfkit.annotations.AnnotationType;
import com.pspdfkit.annotations.configuration.AnnotationConfiguration;
import com.pspdfkit.annotations.configuration.FreeTextAnnotationConfiguration;
Expand All @@ -49,10 +50,14 @@
import com.pspdfkit.document.PdfDocument;
import com.pspdfkit.document.PdfDocumentLoader;
import com.pspdfkit.document.formatters.DocumentJsonFormatter;
import com.pspdfkit.document.formatters.XfdfFormatter;
import com.pspdfkit.document.providers.ContentResolverDataProvider;
import com.pspdfkit.document.providers.DataProvider;
import com.pspdfkit.exceptions.InvalidPasswordException;
import com.pspdfkit.forms.ChoiceFormElement;
import com.pspdfkit.forms.ComboBoxFormElement;
import com.pspdfkit.forms.EditableButtonFormElement;
import com.pspdfkit.forms.FormField;
import com.pspdfkit.forms.TextFormElement;
import com.pspdfkit.listeners.OnVisibilityChangedListener;
import com.pspdfkit.listeners.SimpleDocumentListener;
Expand Down Expand Up @@ -90,6 +95,8 @@

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -226,7 +233,7 @@ public void inject(FragmentManager fragmentManager, EventDispatcher eventDispatc

public void setFragmentTag(String fragmentTag) {
this.fragmentTag = fragmentTag;
setupFragment();
setupFragment(false);
}

public void setInitialConfiguration(PdfActivityConfiguration configuration) {
Expand All @@ -253,7 +260,7 @@ public void setConfiguration(PdfActivityConfiguration configuration) {
removeFragment(false);
}
this.configuration = configuration;
setupFragment();
setupFragment(false);
}

public PdfActivityConfiguration getConfiguration() {
Expand All @@ -271,7 +278,7 @@ public void setCustomToolbarItems(final ArrayList toolbarItems) {

public void setAnnotationConfiguration(final Map<AnnotationType,AnnotationConfiguration> annotationsConfigurations) {
this.annotationsConfigurations = annotationsConfigurations;
setupFragment();
setupFragment(false);
}

public void setDocumentPassword(@Nullable String documentPassword) {
Expand Down Expand Up @@ -307,10 +314,10 @@ public void setDocument(@Nullable String documentPath) {
.observeOn(AndroidSchedulers.mainThread())
.subscribe(imageDocument -> {
PdfView.this.document = imageDocument.getDocument();
setupFragment();
setupFragment(false);
}, throwable -> {
PdfView.this.document = null;
setupFragment();
setupFragment(false);
eventDispatcher.dispatchEvent(new PdfViewDocumentLoadFailedEvent(getId(), throwable.getMessage()));
});
} else {
Expand All @@ -319,18 +326,21 @@ public void setDocument(@Nullable String documentPath) {
.observeOn(AndroidSchedulers.mainThread())
.subscribe(pdfDocument -> {
PdfView.this.document = pdfDocument;
setupFragment();
setupFragment(false);
}, throwable -> {
PdfView.this.document = null;
setupFragment();
eventDispatcher.dispatchEvent(new PdfViewDocumentLoadFailedEvent(getId(), throwable.getMessage()));
// The Android SDK will present password UI, do not emit an error.
if (!(throwable instanceof InvalidPasswordException)) {
PdfView.this.document = null;
eventDispatcher.dispatchEvent(new PdfViewDocumentLoadFailedEvent(getId(), throwable.getMessage()));
}
setupFragment(true);
});
}
}

public void setPageIndex(int pageIndex) {
this.pageIndex = pageIndex;
setupFragment();
setupFragment(false);
}

public void setDisableDefaultActionForTappedAnnotations(boolean disableDefaultActionForTappedAnnotations) {
Expand Down Expand Up @@ -440,8 +450,8 @@ public void setHideDefaultToolbar(boolean hideDefaultToolbar) {
}));
}

private void setupFragment() {
if (fragmentTag != null && configuration != null && document != null) {
private void setupFragment(boolean recreate) {
if (fragmentTag != null && configuration != null && (document != null || recreate == true)) {
PdfUiFragment pdfFragment = (PdfUiFragment) fragmentManager.findFragmentByTag(fragmentTag);
if (pdfFragment != null &&
(pdfFragment.getArguments() == null ||
Expand All @@ -454,10 +464,16 @@ private void setupFragment() {
}

if (pdfFragment == null) {
pdfFragment = PdfUiFragmentBuilder.fromDocumentDescriptor(getContext(), DocumentDescriptor.fromDocument(document))
if (recreate == true) {
pdfFragment = PdfUiFragmentBuilder.fromUri(getContext(), Uri.parse(documentPath)).fragmentClass(ReactPdfUiFragment.class).build();
} else if (document != null) {
pdfFragment = PdfUiFragmentBuilder.fromDocumentDescriptor(getContext(), DocumentDescriptor.fromDocument(document))
.configuration(configuration)
.fragmentClass(ReactPdfUiFragment.class)
.build();
} else {
return;
}
// We put our internal id so we can track if this fragment belongs to us, used to handle orphaned fragments after hot reloads.
pdfFragment.getArguments().putInt(ARG_ROOT_ID, internalId);
prepareFragment(pdfFragment, true);
Expand Down Expand Up @@ -710,8 +726,6 @@ public Single<List<Annotation>> getAllAnnotations(@Nullable final String type) {
.toList();
}



public Disposable addAnnotation(final int requestId, ReadableMap annotation) {
return getCurrentPdfFragment().map(PdfFragment::getDocument).subscribeOn(Schedulers.io())
.map(pdfDocument -> {
Expand Down Expand Up @@ -881,6 +895,65 @@ public Maybe<Boolean> setFormFieldValue(@NonNull String formElementName, @NonNul
});
}

public Disposable importXFDF(final int requestId, String filePath) {

if (Uri.parse(filePath).getScheme() == null) {
filePath = FILE_SCHEME + filePath;
}
if (fragment == null || fragment.getDocument() == null) {
return null;
}

return XfdfFormatter.parseXfdfAsync(fragment.getDocument(), new ContentResolverDataProvider(Uri.parse(filePath)))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(annotations -> {
for (Annotation annotation : annotations) {
fragment.getDocument().getAnnotationProvider().addAnnotationToPage(annotation);
}
JSONObject result = new JSONObject();
result.put("success", true);
eventDispatcher.dispatchEvent(new PdfViewDataReturnedEvent(getId(), requestId, result));
}, throwable -> {
eventDispatcher.dispatchEvent(new PdfViewDataReturnedEvent(getId(), requestId, throwable));
});
}

public Disposable exportXFDF(final int requestId, String filePath) {

if (Uri.parse(filePath).getScheme() == null) {
filePath = FILE_SCHEME + filePath;
}
if (fragment == null || fragment.getDocument() == null) {
return null;
}

try {
final OutputStream outputStream = getContext().getContentResolver().openOutputStream(Uri.parse(filePath));
if (outputStream == null) return null;

List<Annotation> annotations = fragment.getDocument().getAnnotationProvider().getAllAnnotationsOfType(AnnotationProvider.ALL_ANNOTATION_TYPES);
List<FormField> formFields = fragment.getDocument().getFormProvider().getFormFields();

String finalFilePath = filePath;
return XfdfFormatter.writeXfdfAsync(fragment.getDocument(), annotations, formFields, outputStream)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(() -> {
JSONObject result = new JSONObject();
result.put("success", true);
result.put("filePath", finalFilePath);
eventDispatcher.dispatchEvent(new PdfViewDataReturnedEvent(getId(), requestId, result));
}, throwable -> {
eventDispatcher.dispatchEvent(new PdfViewDataReturnedEvent(getId(), requestId, throwable));
}
);
} catch (final FileNotFoundException ignored) {
eventDispatcher.dispatchEvent(new PdfViewDataReturnedEvent(getId(), requestId, ignored));
}
return null;
}

public JSONObject convertConfiguration() {
try {
JSONObject config = new JSONObject();
Expand Down
Loading

0 comments on commit dc6971a

Please sign in to comment.