Skip to content

Commit

Permalink
Merge pull request #308 from PSPDFKit/reinhard/save-document-promise
Browse files Browse the repository at this point in the history
Make saveCurrentDocument and setFormFieldValue return a promise
  • Loading branch information
Reinhard Hafenscher authored Oct 28, 2019
2 parents 35de88e + a43aaed commit 64500f0
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 84 deletions.
26 changes: 23 additions & 3 deletions android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down
77 changes: 41 additions & 36 deletions android/src/main/java/com/pspdfkit/views/PdfView.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<List<Annotation>> getAnnotations(final int pageIndex, @Nullable final String type) {
Expand Down Expand Up @@ -658,49 +663,49 @@ public void run() {

}

public Disposable setFormFieldValue(@NonNull String formElementName, @NonNull final String value) {
public Maybe<Boolean> setFormFieldValue(@NonNull String formElementName, @NonNull final String value) {
return document.getFormProvider().getFormElementWithNameAsync(formElementName)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<FormElement>() {

@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<Integer> 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<Integer> 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<Integer> 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;
});
}
}
30 changes: 27 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion ios/RCTPSPDFKit/RCTPSPDFKitView.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ NS_ASSUME_NONNULL_BEGIN

/// Forms
- (NSDictionary<NSString *, NSString *> *)getFormFieldValue:(NSString *)fullyQualifiedName;
- (void)setFormFieldValue:(NSString *)value fullyQualifiedName:(NSString *)fullyQualifiedName;
- (BOOL)setFormFieldValue:(NSString *)value fullyQualifiedName:(NSString *)fullyQualifiedName;

// Toolbar buttons customizations
- (void)setLeftBarButtonItems:(nullable NSArray <NSString *> *)items forViewMode:(nullable NSString *) viewMode animated:(BOOL)animated;
Expand Down
16 changes: 12 additions & 4 deletions ios/RCTPSPDFKit/RCTPSPDFKitView.m
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 7 additions & 2 deletions ios/RCTPSPDFKit/RCTPSPDFKitViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});
}

Expand Down
42 changes: 24 additions & 18 deletions samples/Catalog/Catalog.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -712,24 +712,30 @@ class PdfViewFormFillingScreen extends Component<{}> {
<Button
onPress={() => {
// Fill Text Form Fields.
this.refs.pdfView.setFormFieldValue("Name_Last", "Appleseed");
this.refs.pdfView.setFormFieldValue("Name_First", "John");
this.refs.pdfView.setFormFieldValue(
"Address_1",
"1 Infinite Loop"
);
this.refs.pdfView.setFormFieldValue("City", "Cupertino");
this.refs.pdfView.setFormFieldValue("STATE", "CA");
this.refs.pdfView.setFormFieldValue("SSN", "123456789");
this.refs.pdfView.setFormFieldValue(
"Telephone_Home",
"(123) 456-7890"
);
this.refs.pdfView.setFormFieldValue("Birthdate", "1/1/1983");

// Select a button form elements.
this.refs.pdfView.setFormFieldValue("Sex.0", "selected");
this.refs.pdfView.setFormFieldValue("PHD", "selected");
Promise.all(
this.refs.pdfView.setFormFieldValue("Name_Last", "Appleseed"),
this.refs.pdfView.setFormFieldValue("Name_First", "John"),
this.refs.pdfView.setFormFieldValue(
"Address_1",
"1 Infinite Loop"
),
this.refs.pdfView.setFormFieldValue("City", "Cupertino"),
this.refs.pdfView.setFormFieldValue("STATE", "CA"),
this.refs.pdfView.setFormFieldValue("SSN", "123456789"),
this.refs.pdfView.setFormFieldValue(
"Telephone_Home",
"(123) 456-7890"
),
this.refs.pdfView.setFormFieldValue("Birthdate", "1/1/1983"),

// Select a button form elements.
this.refs.pdfView.setFormFieldValue("Sex.0", "selected"),
this.refs.pdfView.setFormFieldValue("PHD", "selected")
).then(result => {
// Called when all form field values were set.
// If you want to fill forms then save the document this is the place to do it.
alert("All forms filled!");
});
}}
title="Fill Forms"
/>
Expand Down
Loading

0 comments on commit 64500f0

Please sign in to comment.