diff --git a/android/src/main/java/com/pspdfkit/react/ConfigurationAdapter.java b/android/src/main/java/com/pspdfkit/react/ConfigurationAdapter.java index 96a4381a..7c8284e7 100644 --- a/android/src/main/java/com/pspdfkit/react/ConfigurationAdapter.java +++ b/android/src/main/java/com/pspdfkit/react/ConfigurationAdapter.java @@ -14,6 +14,7 @@ package com.pspdfkit.react; import android.content.Context; +import android.graphics.Color; import android.util.Log; import androidx.annotation.NonNull; @@ -31,8 +32,11 @@ import com.pspdfkit.configuration.page.PageScrollDirection; import com.pspdfkit.configuration.page.PageScrollMode; import com.pspdfkit.configuration.sharing.ShareFeatures; +import com.pspdfkit.configuration.signatures.SignatureColorOptions; +import com.pspdfkit.configuration.signatures.SignatureCreationMode; import com.pspdfkit.configuration.signatures.SignatureSavingStrategy; import com.pspdfkit.preferences.PSPDFKitPreferences; +import com.pspdfkit.react.helper.ColorHelper; import java.util.ArrayList; import java.util.Collections; @@ -114,6 +118,10 @@ public class ConfigurationAdapter { private static final String ENABLE_MAGNIFIER = "enableMagnifier"; private static final String ENABLED_MEASUREMENT_TOOL_SNAPPING = "enableMeasurementToolSnapping"; + // Signature presentation options + private static final String SIGNATURE_CREATION_MODES = "signatureCreationModes"; + private static final String SIGNATURE_COLOR_OPTIONS = "signatureColorOptions"; + // Deprecated Options /** * @deprecated This key word was deprecated with PSPDFKit for React Native 2.1. @@ -322,6 +330,14 @@ public ConfigurationAdapter(@NonNull final Context context, ReadableMap configur if (key != null) { configureMeasurementToolSnappingEnabled(context, configuration.getBoolean(key)); } + key = getKeyOrNull(configuration, SIGNATURE_CREATION_MODES); + if (key != null) { + configureSignatureCreationModes(configuration.getArray(key)); + } + key = getKeyOrNull(configuration, SIGNATURE_COLOR_OPTIONS); + if (key != null) { + configureSignatureColorOptions(context, configuration.getArray(key)); + } } } @@ -704,6 +720,66 @@ private void configureMeasurementToolSnappingEnabled(Context context, final Bool PSPDFKitPreferences.get(context).setMeasurementSnappingEnabled(snappingEnabled); } + private void configureSignatureCreationModes(@Nullable final ReadableArray signatureCreationModes) { + if (signatureCreationModes == null) { + // If explicit null is passed we disable all signature modes. + configuration.signatureCreationModes(new ArrayList<>()); + return; + } + List sigCreationModesList = signatureCreationModes.toArrayList(); + + // Finally create the actual list of enabled signature creation modes. + List parsedTypes = new ArrayList<>(); + for (Object item : sigCreationModesList) { + String signatureCreationMode = item.toString(); + try { + parsedTypes.add(SignatureCreationMode.valueOf(signatureCreationMode.toUpperCase(Locale.ENGLISH))); + } catch (IllegalArgumentException ex) { + Log.e(LOG_TAG, + String.format("Illegal option %s provided for configuration option %s. Skipping this %s.", signatureCreationMode, SIGNATURE_CREATION_MODES, signatureCreationMode), + ex); + } + } + configuration.signatureCreationModes(parsedTypes); + } + + private void configureSignatureColorOptions(final Context context, @Nullable final ReadableArray signatureCreationColors) { + if (signatureCreationColors == null) { + return; + } + + List sigCreationColors = signatureCreationColors.toArrayList(); + + SignatureColorOptions defaultColors = SignatureColorOptions.fromDefaults(); + int[] configuredColors = new int[] { defaultColors.option1(context), + defaultColors.option2(context), defaultColors.option3(context) }; + + int i = 0; + for (Object rgbaColorOrName : sigCreationColors) { + // only 3 colors are supported + if (i == 3) break; + + String color = rgbaColorOrName.toString(); + + // attempt to resolve colors, if no match + // we'll use the default value at this index + if (color.contains("rgb(")) { + configuredColors[i] = ColorHelper.rgb(color); + } + else { + // hex or named colors + configuredColors[i] = Color.parseColor(color); + } + + i++; + } + + configuration.signatureColorOptions(SignatureColorOptions.fromColorInt( + configuredColors[0], + configuredColors[1], + configuredColors[2])); + } + public PdfActivityConfiguration build() { return configuration.build(); } diff --git a/ios/RCTPSPDFKit/Converters/RCTConvert+PSPDFConfiguration.m b/ios/RCTPSPDFKit/Converters/RCTConvert+PSPDFConfiguration.m index accbe1a2..7f89d57f 100644 --- a/ios/RCTPSPDFKit/Converters/RCTConvert+PSPDFConfiguration.m +++ b/ios/RCTPSPDFKit/Converters/RCTConvert+PSPDFConfiguration.m @@ -132,6 +132,10 @@ #define BookmarkSortOrderMap @{@"custom" : @(PSPDFBookmarkManagerSortOrderCustom), \ @"pageBased" : @(PSPDFBookmarkManagerSortOrderPageBased)} \ +#define SignatureCreationModeMap @{@"draw": @(PSPDFSignatureCreationModeDraw), \ + @"image": @(PSPDFSignatureCreationModeImage), \ + @"type": @(PSPDFSignatureCreationModeType)} \ + @implementation RCTConvert (PSPDFConfiguration) + (PSPDFConfiguration *)PSPDFConfiguration:(id)json { @@ -563,6 +567,19 @@ + (NSDictionary *)convertConfiguration:(PSPDFViewController *)viewController { [convertedConfiguration setObject:[RCTConvert findKeyForValue:configuration.bookmarkSortOrder inDictionary:BookmarkSortOrderMap] forKey:@"iOSBookmarkSortOrder"]; + [convertedConfiguration setObject:[RCTConvert findKeysForValues:[NSSet setWithArray:configuration.signatureCreationConfiguration.availableModes] + inDictionary:SignatureCreationModeMap] + forKey:@"signatureCreationModes"]; + + NSMutableArray *signatureCreationColors = [NSMutableArray array]; + [configuration.signatureCreationConfiguration.colors enumerateObjectsUsingBlock:^(UIColor * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + + NSString *hexColor = [NSString stringWithFormat:@"#%02lX", [obj hex]]; + + [signatureCreationColors addObject:hexColor]; + }]; + [convertedConfiguration setObject:signatureCreationColors forKey:@"signatureCreationColors"]; + return convertedConfiguration; } @@ -694,6 +711,8 @@ - (void)setupFromJSON:(id)json { self.editableAnnotationTypes = [editableTypes copy]; } + [self setRCTSignatureCreationConfiguration:dictionary]; + // Deprecated Options // Use `scrollDirection` instead. @@ -739,4 +758,46 @@ - (void)setRCTSharingConfigurations:(NSArray *)sharingConfigurat self.sharingConfigurations = rnSharingConfigurations; } +- (void)setRCTSignatureCreationConfiguration:(NSDictionary *)configuration { + PSPDFSignatureCreationConfigurationBuilder *builder = [PSPDFSignatureCreationConfigurationBuilder alloc]; + + // important: set all default values + [builder reset]; + + if (configuration[@"signatureCreationModes"]) { + NSSet *selectedModes = [NSSet setWithArray:[RCTConvert NSArray:configuration[@"signatureCreationModes"]]]; + + NSMutableArray *mappedValues = [NSMutableArray array]; + for (NSString *signatureCreationModeString in selectedModes) { + NSNumber *value = [SignatureCreationModeMap valueForKey:signatureCreationModeString]; + if (value != nil) { + [mappedValues addObject:value]; + } + } + + builder.availableModes = mappedValues; + } + + if (configuration[@"signatureColorOptions"]) { + NSArray *signatureColors = [RCTConvert NSArray:configuration[@"signatureColorOptions"]]; + + NSMutableArray *resolvedColors = [NSMutableArray array]; + for (NSString *colorString in signatureColors) { + if ([colorString hasPrefix:@"rgb("]) { + [resolvedColors addObject: [UIColor rgb:colorString]]; + } + else if ([colorString hasPrefix:@"#"]){ + [resolvedColors addObject: [[UIColor new] initWithHexString:colorString]]; + } + else { + [resolvedColors addObject: [UIColor colorFromName:colorString]]; + } + } + + builder.colors = resolvedColors; + } + + self.signatureCreationConfiguration = [builder build]; +} + @end diff --git a/ios/RCTPSPDFKit/UIColor.swift b/ios/RCTPSPDFKit/UIColor.swift index ef26c70f..b80f7146 100644 --- a/ios/RCTPSPDFKit/UIColor.swift +++ b/ios/RCTPSPDFKit/UIColor.swift @@ -11,7 +11,7 @@ import UIKit extension UIColor { - public convenience init?(hexString: String) { + @objc public convenience init?(hexString: String) { let r, g, b, a: CGFloat if hexString.hasPrefix("#") { @@ -51,7 +51,7 @@ extension UIColor { } - public static func colorFromName(_ name: String) -> UIColor? { + @objc public static func colorFromName(_ name: String) -> UIColor? { let selector = Selector("\(name)Color") if UIColor.self.responds(to: selector) { let color = UIColor.self.perform(selector).takeUnretainedValue() @@ -61,7 +61,7 @@ extension UIColor { return nil } - public static func rgb(_ colorValue: String) -> UIColor? { + @objc public static func rgb(_ colorValue: String) -> UIColor? { let colorsComponentString: String = colorValue.replacingOccurrences(of: "rgb(", with: "").replacingOccurrences(of: ")", with: "").replacingOccurrences(of: " ", with: "") let colorComponents = colorsComponentString.components(separatedBy: ",") @@ -104,4 +104,12 @@ extension UIColor { + Int(green * 255) << 8 + Int(blue * 255) } + + @objc public var hex: Int { + var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0 + getRed(&red, green: &green, blue: &blue, alpha: &alpha) + return Int(red * 255) << 16 + + Int(green * 255) << 8 + + Int(blue * 255) + } } diff --git a/src/configuration/PDFConfiguration.ts b/src/configuration/PDFConfiguration.ts index 688d267f..7205b244 100644 --- a/src/configuration/PDFConfiguration.ts +++ b/src/configuration/PDFConfiguration.ts @@ -101,7 +101,9 @@ import { MeasurementValueConfiguration } from './../measurements/Measurements'; * @property { PDFConfiguration.BooleanType } [syncAnnotations] Indicates whether document annotations should be synced with the Instant server. * @property { Measurements.MeasurementValueConfiguration[] } [measurementValueConfigurations] The array of ```MeasurementValueConfiguration``` objects that should be applied to the document. * @property { PDFConfiguration.RemoteDocumentConfiguration } [remoteDocumentConfiguration] The configuration when downloading a document from a remote URL. - */ + * @property { PDFConfiguration.SignatureCreationModes[] } [signatureCreationModes] The signature creation modes that should be available in the signature picker. + * @property { PDFConfiguration.SignatureColorOptions[] } [signatureColorOptions] The color options that should be available in the signature picker, max of 3 colors are supported. If all 3 colors are not provided, defaults will be used in their place. +*/ export class PDFConfiguration { @@ -475,6 +477,16 @@ export class PDFConfiguration { * The configuration when downloading a document from a remote URL. */ remoteDocumentConfiguration?: RemoteDocumentConfiguration; + + /** + * The signature creation modes that should be available in the signature picker. + */ + signatureCreationModes?: PDFConfiguration.SignatureCreationModes[]; + + /** + * The signature color options that should be available in the signature picker, max of 3 colors are supported. If all 3 colors are not provided, defaults will be used in their place. + */ + signatureColorOptions?: PDFConfiguration.SignatureColorOptions[]; } export namespace PDFConfiguration { @@ -1000,6 +1012,37 @@ export namespace PDFConfiguration { */ PAGE_BASED: 'pageBased' } as const; + + /** + * The possible ways in which the user can input their signature. + * @readonly + * @enum {string} SignatureCreationModes + */ + export const SignatureCreationModes = { + /** + * The user draws their signature. For example using a finger or stylus. + */ + DRAW: 'draw', + /** + * The user selects an existing image of their signature from their photo library or files, or takes + * a photo of their signature written on a piece of paper. + */ + IMAGE: 'image', + /** + * The user types their name and selects a style for their signature from a small number of fonts. + */ + TYPE: 'type' + } as const; + + /** + * Color defined by a hex string of RGB values. + */ + export type HexColor = `#${string}`; + + /** + * Color defined by RGB values. + */ + export type RGBColor = `rgb(${number},${number},${number})`; export type BooleanType = ValueOf; export type ScrollDirection = ValueOf; @@ -1023,6 +1066,8 @@ export namespace PDFConfiguration { export type IOSLinkAction = ValueOf; export type IOSDrawCreateMode = ValueOf; export type IOSBookmarkSortOrder = ValueOf; + export type SignatureCreationModes = ValueOf; + export type SignatureColorOptions = HexColor | RGBColor | string; } /** @@ -1047,4 +1092,4 @@ T extends `${infer F1}${infer F2}${infer R}` ? ( T extends `${infer F}${infer R}` ? `${Uppercase | Lowercase}${AnyCase}` : ""; -type ValueOf = T[keyof T]; \ No newline at end of file +type ValueOf = T[keyof T];