diff --git a/android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java b/android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java index f7f0be2f..348217e1 100644 --- a/android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java +++ b/android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java @@ -171,7 +171,15 @@ public void receiveCommand(final PdfView root, int commandId, @Nullable Readable root.exitCurrentlyActiveMode(); break; case COMMAND_SAVE_CURRENT_DOCUMENT: - root.saveCurrentDocument(); + if (args != null) { + final int requestId = args.getInt(0); + try { + boolean result = root.saveCurrentDocument(); + root.getEventDispatcher().dispatchEvent(new PdfViewDataReturnedEvent(root.getId(), requestId, result)); + } catch (Exception e) { + root.getEventDispatcher().dispatchEvent(new PdfViewDataReturnedEvent(root.getId(), requestId, e)); + } + } break; case COMMAND_GET_ANNOTATIONS: if (args != null) { @@ -241,8 +249,20 @@ public void accept(JSONObject jsonObject) { } break; case COMMAND_SET_FORM_FIELD_VALUE: - if (args != null && args.size() == 2) { - annotationDisposables.add(root.setFormFieldValue(args.getString(0), args.getString(1))); + if (args != null && args.size() == 3) { + final int requestId = args.getInt(0); + Disposable annotationDisposable = root.setFormFieldValue(args.getString(1), args.getString(2)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(fieldSet -> { + root.getEventDispatcher().dispatchEvent(new PdfViewDataReturnedEvent(root.getId(), requestId, fieldSet)); + }, throwable -> { + root.getEventDispatcher().dispatchEvent(new PdfViewDataReturnedEvent(root.getId(), requestId, throwable)); + },() -> { + // Called when no form field was found. + root.getEventDispatcher().dispatchEvent(new PdfViewDataReturnedEvent(root.getId(), requestId, false)); + }); + annotationDisposables.add(annotationDisposable); } break; } diff --git a/android/src/main/java/com/pspdfkit/views/PdfView.java b/android/src/main/java/com/pspdfkit/views/PdfView.java index 27a33b51..8ef0dbdf 100644 --- a/android/src/main/java/com/pspdfkit/views/PdfView.java +++ b/android/src/main/java/com/pspdfkit/views/PdfView.java @@ -58,6 +58,7 @@ import java.util.concurrent.Callable; import io.reactivex.Completable; +import io.reactivex.Maybe; import io.reactivex.Observable; import io.reactivex.ObservableSource; import io.reactivex.Single; @@ -446,17 +447,21 @@ public void accept(PdfFragment pdfFragment) { })); } - public void saveCurrentDocument() { + public boolean saveCurrentDocument() throws Exception { if (fragment != null) { try { if (document.saveIfModified()) { // Since the document listeners won't be called when manually saving we also dispatch this event here. eventDispatcher.dispatchEvent(new PdfViewDocumentSavedEvent(getId())); + return true; } + return false; } catch (Exception e) { eventDispatcher.dispatchEvent(new PdfViewDocumentSaveFailedEvent(getId(), e.getMessage())); + throw e; } } + return false; } public Single> getAnnotations(final int pageIndex, @Nullable final String type) { @@ -658,49 +663,49 @@ public void run() { } - public Disposable setFormFieldValue(@NonNull String formElementName, @NonNull final String value) { + public Maybe setFormFieldValue(@NonNull String formElementName, @NonNull final String value) { return document.getFormProvider().getFormElementWithNameAsync(formElementName) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Consumer() { - - @Override - public void accept(FormElement formElement) { - if (formElement instanceof TextFormElement) { - TextFormElement textFormElement = (TextFormElement) formElement; - textFormElement.setText(value); - } else if (formElement instanceof EditableButtonFormElement) { - EditableButtonFormElement editableButtonFormElement = (EditableButtonFormElement) formElement; - if (value.equalsIgnoreCase("selected")) { - editableButtonFormElement.select(); - } else if (value.equalsIgnoreCase("deselected")) { - editableButtonFormElement.deselect(); - } - } else if (formElement instanceof ChoiceFormElement) { - ChoiceFormElement choiceFormElement = (ChoiceFormElement) formElement; + .map(formElement -> { + if (formElement instanceof TextFormElement) { + TextFormElement textFormElement = (TextFormElement) formElement; + textFormElement.setText(value); + return true; + } else if (formElement instanceof EditableButtonFormElement) { + EditableButtonFormElement editableButtonFormElement = (EditableButtonFormElement) formElement; + if (value.equalsIgnoreCase("selected")) { + editableButtonFormElement.select(); + } else if (value.equalsIgnoreCase("deselected")) { + editableButtonFormElement.deselect(); + } + return true; + } else if (formElement instanceof ChoiceFormElement) { + ChoiceFormElement choiceFormElement = (ChoiceFormElement) formElement; + try { + int selectedIndex = Integer.parseInt(value); + List selectedIndices = new ArrayList<>(); + selectedIndices.add(selectedIndex); + choiceFormElement.setSelectedIndexes(selectedIndices); + return true; + } catch (NumberFormatException e) { try { - int selectedIndex = Integer.parseInt(value); + // Maybe it's multiple indices. + JSONArray indices = new JSONArray(value); List selectedIndices = new ArrayList<>(); - selectedIndices.add(selectedIndex); + for (int i = 0; i < indices.length(); i++) { + selectedIndices.add(indices.getInt(i)); + } choiceFormElement.setSelectedIndexes(selectedIndices); - } catch (NumberFormatException e) { - try { - // Maybe it's multiple indices. - JSONArray indices = new JSONArray(value); - List selectedIndices = new ArrayList<>(); - for (int i = 0; i < indices.length(); i++) { - selectedIndices.add(indices.getInt(i)); - } - choiceFormElement.setSelectedIndexes(selectedIndices); - } catch (JSONException ex) { - // This isn't an index maybe we can set a custom value on a combobox. - if (formElement instanceof ComboBoxFormElement) { - ((ComboBoxFormElement) formElement).setCustomText(value); - } + return true; + } catch (JSONException ex) { + // This isn't an index maybe we can set a custom value on a combobox. + if (formElement instanceof ComboBoxFormElement) { + ((ComboBoxFormElement) formElement).setCustomText(value); + return true; } } } } + return false; }); } } diff --git a/index.js b/index.js index d6245d1d..23760132 100644 --- a/index.js +++ b/index.js @@ -131,15 +131,27 @@ class PSPDFKitView extends React.Component { /** * Saves the currently opened document. + * + * Returns a promise resolving to true if the document was saved, and false otherwise. */ saveCurrentDocument = function() { if (Platform.OS === "android") { + let requestId = this._nextRequestId++; + let requestMap = this._requestMap; + + // We create a promise here that will be resolved once onDataReturned is called. + let promise = new Promise(function(resolve, reject) { + requestMap[requestId] = { resolve: resolve, reject: reject }; + }); + UIManager.dispatchViewManagerCommand( findNodeHandle(this.refs.pdfView), this._getViewManagerConfig("RCTPSPDFKitView").Commands .saveCurrentDocument, - [] + [requestId] ); + + return promise; } else if (Platform.OS === "ios") { return NativeModules.PSPDFKitViewManager.saveCurrentDocument( findNodeHandle(this.refs.pdfView) @@ -381,17 +393,29 @@ class PSPDFKitView extends React.Component { * * @param fullyQualifiedName The fully qualified name of the form element. * @param value The string value form element. For button form elements pass 'selected' or 'deselected'. For choice form elements, pass the index of the choice to select, for example '1'. + * + * Returns a promise resolving to true if the value was set, and false otherwise. */ setFormFieldValue = function(fullyQualifiedName, value) { if (Platform.OS === "android") { + let requestId = this._nextRequestId++; + let requestMap = this._requestMap; + + // We create a promise here that will be resolved once onDataReturned is called. + let promise = new Promise(function(resolve, reject) { + requestMap[requestId] = { resolve: resolve, reject: reject }; + }); + UIManager.dispatchViewManagerCommand( findNodeHandle(this.refs.pdfView), this._getViewManagerConfig("RCTPSPDFKitView").Commands .setFormFieldValue, - [fullyQualifiedName, value] + [requestId, fullyQualifiedName, value] ); + + return promise; } else if (Platform.OS === "ios") { - NativeModules.PSPDFKitViewManager.setFormFieldValue( + return NativeModules.PSPDFKitViewManager.setFormFieldValue( value, fullyQualifiedName, findNodeHandle(this.refs.pdfView) diff --git a/ios/RCTPSPDFKit/RCTPSPDFKitView.h b/ios/RCTPSPDFKit/RCTPSPDFKitView.h index 5a5f40ae..546d96a8 100644 --- a/ios/RCTPSPDFKit/RCTPSPDFKitView.h +++ b/ios/RCTPSPDFKit/RCTPSPDFKitView.h @@ -48,7 +48,7 @@ NS_ASSUME_NONNULL_BEGIN /// Forms - (NSDictionary *)getFormFieldValue:(NSString *)fullyQualifiedName; -- (void)setFormFieldValue:(NSString *)value fullyQualifiedName:(NSString *)fullyQualifiedName; +- (BOOL)setFormFieldValue:(NSString *)value fullyQualifiedName:(NSString *)fullyQualifiedName; // Toolbar buttons customizations - (void)setLeftBarButtonItems:(nullable NSArray *)items forViewMode:(nullable NSString *) viewMode animated:(BOOL)animated; diff --git a/ios/RCTPSPDFKit/RCTPSPDFKitView.m b/ios/RCTPSPDFKit/RCTPSPDFKitView.m index ceff59d6..acc24afc 100644 --- a/ios/RCTPSPDFKit/RCTPSPDFKitView.m +++ b/ios/RCTPSPDFKit/RCTPSPDFKitView.m @@ -310,35 +310,43 @@ - (BOOL)addAnnotations:(id)jsonAnnotations error:(NSError *_Nullable *)error { return @{@"error": @"Failed to get the form field value."}; } -- (void)setFormFieldValue:(NSString *)value fullyQualifiedName:(NSString *)fullyQualifiedName { +- (BOOL)setFormFieldValue:(NSString *)value fullyQualifiedName:(NSString *)fullyQualifiedName { if (fullyQualifiedName.length == 0) { NSLog(@"Invalid fully qualified name."); - return; + return NO; } PSPDFDocument *document = self.pdfController.document; - VALIDATE_DOCUMENT(document) - + VALIDATE_DOCUMENT(document, NO) + + BOOL success = NO; for (PSPDFFormElement *formElement in document.formParser.forms) { if ([formElement.fullyQualifiedFieldName isEqualToString:fullyQualifiedName]) { if ([formElement isKindOfClass:PSPDFButtonFormElement.class]) { if ([value isEqualToString:@"selected"]) { [(PSPDFButtonFormElement *)formElement select]; + success = YES; } else if ([value isEqualToString:@"deselected"]) { [(PSPDFButtonFormElement *)formElement deselect]; + success = YES; } } else if ([formElement isKindOfClass:PSPDFChoiceFormElement.class]) { ((PSPDFChoiceFormElement *)formElement).selectedIndices = [NSIndexSet indexSetWithIndex:value.integerValue]; + success = YES; } else if ([formElement isKindOfClass:PSPDFTextFieldFormElement.class]) { formElement.contents = value; + success = YES; } else if ([formElement isKindOfClass:PSPDFSignatureFormElement.class]) { NSLog(@"Signature form elements are not supported."); + success = NO; } else { NSLog(@"Unsupported form element."); + success = NO; } break; } } + return success; } #pragma mark - Notifications diff --git a/ios/RCTPSPDFKit/RCTPSPDFKitViewManager.m b/ios/RCTPSPDFKit/RCTPSPDFKitViewManager.m index 6ec6dd70..40f35642 100644 --- a/ios/RCTPSPDFKit/RCTPSPDFKitViewManager.m +++ b/ios/RCTPSPDFKit/RCTPSPDFKitViewManager.m @@ -233,10 +233,15 @@ @implementation RCTPSPDFKitViewManager }); } -RCT_EXPORT_METHOD(setFormFieldValue:(nullable NSString *)value fullyQualifiedName:(NSString *)fullyQualifiedName reactTag:(nonnull NSNumber *)reactTag) { +RCT_EXPORT_METHOD(setFormFieldValue:(nullable NSString *)value fullyQualifiedName:(NSString *)fullyQualifiedName reactTag:(nonnull NSNumber *)reactTag resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { dispatch_async(dispatch_get_main_queue(), ^{ RCTPSPDFKitView *component = (RCTPSPDFKitView *)[self.bridge.uiManager viewForReactTag:reactTag]; - [component setFormFieldValue:value fullyQualifiedName:fullyQualifiedName]; + BOOL success = [component setFormFieldValue:value fullyQualifiedName:fullyQualifiedName]; + if (success) { + resolve(@(success)); + } else { + reject(@"error", @"Failed to set form field value.", nil); + } }); } diff --git a/samples/Catalog/Catalog.android.js b/samples/Catalog/Catalog.android.js index 06a7aaf3..9588cf4e 100644 --- a/samples/Catalog/Catalog.android.js +++ b/samples/Catalog/Catalog.android.js @@ -712,24 +712,30 @@ class PdfViewFormFillingScreen extends Component<{}> {