Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bridge Instant Example from PSPDFKit Catalog to the NativeCatalog React Native project #362

Merged
merged 4 commits into from
Apr 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-pspdfkit",
"version": "1.28.6",
"version": "1.28.7",
"description": "A React Native module for the PSPDFKit library.",
"keywords": [
"react native",
Expand Down
2 changes: 1 addition & 1 deletion samples/Catalog/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Catalog",
"version": "1.28.6",
"version": "1.28.7",
"private": true,
"scripts": {
"start": "react-native start",
Expand Down
65 changes: 50 additions & 15 deletions samples/NativeCatalog/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ const examples = [
name: 'Manual Signing',
description:
'Shows how to start the signing flow using a react-native button linked to our CustomPdfView.',
action: component => {
action: (component) => {
if (Platform.OS === 'android') {
requestExternalStoragePermission(function() {
extractFromAssetsIfMissing('Form_example.pdf', function() {
requestExternalStoragePermission(function () {
extractFromAssetsIfMissing('Form_example.pdf', function () {
component.props.navigation.navigate('ManualSigning');
});
});
Expand All @@ -45,10 +45,10 @@ const examples = [
name: 'Watermark',
description:
'Shows how to watermark a PDF that is loaded in our CustomPdfView',
action: component => {
action: (component) => {
if (Platform.OS === 'android') {
requestExternalStoragePermission(function() {
extractFromAssetsIfMissing('Form_example.pdf', function() {
requestExternalStoragePermission(function () {
extractFromAssetsIfMissing('Form_example.pdf', function () {
component.props.navigation.navigate('Watermark');
});
});
Expand All @@ -61,10 +61,10 @@ const examples = [
name: 'Watermark on Startup',
description:
'Shows how to watermark a PDF as soon as it is loaded in our CustomPdfView',
action: component => {
action: (component) => {
if (Platform.OS === 'android') {
requestExternalStoragePermission(function() {
extractFromAssetsIfMissing('Form_example.pdf', function() {
requestExternalStoragePermission(function () {
extractFromAssetsIfMissing('Form_example.pdf', function () {
component.props.navigation.navigate('WatermarkStartup');
});
});
Expand All @@ -77,10 +77,10 @@ const examples = [
name: 'Default Annotation Settings',
description:
'Shows how to configure default annotations settings. (Android Only)',
action: component => {
action: (component) => {
if (Platform.OS === 'android') {
requestExternalStoragePermission(function() {
extractFromAssetsIfMissing('Form_example.pdf', function() {
requestExternalStoragePermission(function () {
extractFromAssetsIfMissing('Form_example.pdf', function () {
component.props.navigation.navigate('DefaultAnnotationSettings');
});
});
Expand All @@ -89,6 +89,15 @@ const examples = [
}
},
},
{
name: 'Instant Example',
description: 'Shows the Native Swift Instant Example. (iOS only)',
action: (component) => {
if (Platform.OS === 'ios') {
component.props.navigation.push('InstantExample');
}
},
},
];

class ManualSigningScreen extends Component<{}> {
Expand All @@ -106,7 +115,7 @@ class ManualSigningScreen extends Component<{}> {
ref="pdfView"
document={this.state.documentPath}
style={{flex: 1}}
onDocumentDigitallySigned={event => {
onDocumentDigitallySigned={(event) => {
this.setState({
documentPath: event.nativeEvent.signedDocumentPath,
});
Expand Down Expand Up @@ -157,7 +166,7 @@ class WatermarkScreen extends Component<{}> {
ref="pdfView"
document={this.state.documentPath}
style={{flex: 1}}
onDocumentWatermarked={event => {
onDocumentWatermarked={(event) => {
this.setState({
documentPath: event.nativeEvent.watermarkedDocumentPath,
});
Expand Down Expand Up @@ -209,7 +218,7 @@ class WatermarkStartupScreen extends Component<{}> {
ref="pdfView"
document={this.state.documentPath}
style={{flex: 1}}
onDocumentWatermarked={event => {
onDocumentWatermarked={(event) => {
this.setState({
documentPath: event.nativeEvent.watermarkedDocumentPath,
});
Expand All @@ -220,6 +229,29 @@ class WatermarkStartupScreen extends Component<{}> {
}
}

class InstantExampleScreen extends Component<{}> {
render() {
return (
<View style={{flex: 1}}>
{Platform.OS === 'ios' && <CustomPdfView ref="pdfView" />}
{Platform.OS === 'ios' && (
<Button
onPress={() => {
NativeModules.CustomPdfViewManager.presentInstantExample(
findNodeHandle(this.refs.pdfView),
);
}}
title="Present Instant Example"
/>
)}
{Platform.OS === 'android' && (
<Text>This example isn't supported on Android!</Text>
)}
</View>
);
}
}

class DefaultAnnotationSettingsScreen extends Component<{}> {
render() {
return (
Expand Down Expand Up @@ -259,6 +291,9 @@ export default createAppContainer(
WatermarkStartup: {
screen: WatermarkStartupScreen,
},
InstantExample: {
screen: InstantExampleScreen,
},
DefaultAnnotationSettings: {
screen: DefaultAnnotationSettingsScreen,
},
Expand Down
2 changes: 2 additions & 0 deletions samples/NativeCatalog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ target 'YourApp' do
pod 'react-native-pspdfkit', :path => '../node_modules/react-native-pspdfkit'
- pod 'PSPDFKit', podspec: 'https://customers.pspdfkit.com/cocoapods/YOUR_COCOAPODS_KEY_GOES_HERE/pspdfkit/latest.podspec'
+ pod 'PSPDFKit', podspec: 'https://customers.pspdfkit.com/cocoapods/USE_YOUR_OWN_COCOAPODS_KEY/pspdfkit/latest.podspec'
- pod 'Instant', podspec:'https://customers.pspdfkit.com/cocoapods/YOUR_COCOAPODS_KEY_GOES_HERE/instant/latest.podspec'
+ pod 'Instant', podspec:'https://customers.pspdfkit.com/cocoapods/USE_YOUR_OWN_COCOAPODS_KEY/instant/latest.podspec'

use_native_modules!
end
Expand Down
43 changes: 43 additions & 0 deletions samples/NativeCatalog/ios/InstantExample/InstantDocumentInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// InstantDocumentInfo.swift
// PSPDFKit
//
// Copyright © 2017-2020 PSPDFKit GmbH. All rights reserved.
//
// THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
// AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE PSPDFKIT LICENSE AGREEMENT.
// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
// This notice may not be removed from this file.
//

/// The response from the PSPDFKit for Web examples server API that may be used to load a document layer with Instant.
struct InstantDocumentInfo {
let serverURL: URL
let url: URL
let jwt: String
}

extension InstantDocumentInfo: Equatable {
public static func == (lhs: InstantDocumentInfo, rhs: InstantDocumentInfo) -> Bool {
return lhs.serverURL == rhs.serverURL && lhs.url == rhs.url && lhs.jwt == rhs.jwt
}
}

extension InstantDocumentInfo {
enum JSONKeys: String {
case serverUrl, url, documentId, jwt
}

init?(json: Any) {
guard let dictionary = json as? [String: Any],
let serverUrlString = dictionary[JSONKeys.serverUrl.rawValue] as? String,
let serverURL = URL(string: serverUrlString),
let urlString = dictionary[JSONKeys.url.rawValue] as? String,
let url = URL(string: urlString),
let jwt = dictionary[JSONKeys.jwt.rawValue] as? String else {
return nil
}

self.init(serverURL: serverURL, url: url, jwt: jwt)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//
// Copyright © 2018-2020 PSPDFKit GmbH. All rights reserved.
//
// THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
// AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE PSPDFKIT LICENSE AGREEMENT.
// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
// This notice may not be removed from this file.
//

import PSPDFKitUI

/**
Connects to our public PSPDFKit for Web examples server to present documents managed by PSPDFKit Instant.
This is decoupled from any view controller in order to support loading documents by opening URLs.
*/
public class InstantDocumentPresenter {
/**
Interfaces with our Web examples server to create and access documents.
In your own app you would connect to your own server backend to get Instant document identifiers and authentication tokens.
*/
private lazy var apiClient = WebExamplesAPIClient(presentingViewController: presentingViewController)

/// View controller that can present other view controllers.
private weak var presentingViewController: UIViewController?

/// Initialize a document presenter with a view controller that can present other view controllers.
public init(presentingViewController: UIViewController) {
self.presentingViewController = presentingViewController
}

/// Tries to create a new Instant session.
public func createNewSession() {
loadSession(loadingMessage: "Creating") { completion in
self.apiClient.createNewSession(completion: completion)
}
}

/**
Tries to join an existing Instant session or shows an alert on failure.

- Parameter urlString: An Instant document URL scanned from a barcode or entered by the user.
*/
public func joinExistingSession(withURL urlString: String) {
guard let url = URL(string: urlString) else {
showAlert(withTitle: "Couldn’t Join Group", message: "This is not a link. Please enter an Instant document link.")
return
}

loadSession(loadingMessage: "Verifying") { completion in
self.apiClient.resolveExistingSessionURL(url, completion: completion)
}
}

/**
Loads an Instant session using the specified API call. The passed in closure should run an
asynchronous API call. That closure will be passed another closure to run on completion.
*/
private func loadSession(loadingMessage: String, APICall: @escaping (@escaping WebExamplesAPIClient.CompletionHandler) -> Void) {
let progressHUDItem = StatusHUDItem.indeterminateProgress(withText: loadingMessage)
progressHUDItem.setHUDStyle(.black)

progressHUDItem.push(animated: true, on: presentingViewController?.view.window) {
APICall { result in
DispatchQueue.main.async {
progressHUDItem.pop(animated: true, completion: nil)

switch result {
case let .success(documentInfo):
do {
try self.openDocument(with: documentInfo)
} catch {
self.showAlert(withTitle: "Couldn’t Set Up Instant", message: error.localizedDescription)
}

case .failure(WebExamplesAPIClient.Failure.cancelled):
break // Do not show the alert if user cancelled the request themselves.

case let .failure(otherError):
self.showAlert(withTitle: "Couldn’t Get Instant Document Info", message: otherError.localizedDescription)
}
}
}
}
}

private func openDocument(with info: InstantDocumentInfo) throws {
let instantViewController = try InstantDocumentViewController(documentInfo: info)

let navigationController = UINavigationController(rootViewController: instantViewController)
navigationController.modalPresentationStyle = .fullScreen

presentOnFrontmostViewController(navigationController)
}

private func showAlert(withTitle title: String, message: String) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .cancel))

presentOnFrontmostViewController(alertController)
}

private func presentOnFrontmostViewController(_ viewController: UIViewController) {
guard let rootViewController = presentingViewController?.viewIfLoaded?.window?.rootViewController else {
print("Couldn’t show view controller because no root view controller was found.")
return
}

rootViewController.psc_frontmost.present(viewController, animated: true, completion: nil)
}
}
Loading