diff --git a/ACKNOWLEDGEMENTS.md b/ACKNOWLEDGEMENTS.md index 44045f43..d2acc4eb 100644 --- a/ACKNOWLEDGEMENTS.md +++ b/ACKNOWLEDGEMENTS.md @@ -461,6 +461,36 @@ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. +-------------------------------------------------------------------------------- +// Copyright 2015 The Chromium Authors +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + -------------------------------------------------------------------------------- ## clipper2 (http://www.angusj.com/delphi/clipper.php) @@ -1786,6 +1816,36 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +Copyright 2006 Google Inc. All Rights Reserved. +Author: agl@imperialviolet.org (Adam Langley) + +Copyright (C) 2006 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +This software is a description of processes which may be patented. + +Use of this software may require patent licenses in some countries. +You are directed to annex I of the JBIG2 specification for information. + +Some information could be found at: + http://www.jpeg.org/jbig/index.html + http://www.cl.cam.ac.uk/~mgk25/jbigkit/patents/ + http://www.jpeg.org/public/fcd14492.pdf + http://itscj.ipsj.or.jp/sc29/open/29view/29n55161.doc + + -------------------------------------------------------------------------------- ## koin (https://github.com/InsertKoinIO/koin) @@ -3068,6 +3128,36 @@ I, Matt McCutchen, the sole author of the original Big Integer Library, waive my copyright to it, placing it in the public domain. The library comes with absolutely no warranty. +-------------------------------------------------------------------------------- +MIT License + +Copyright (c) 2021 The fast_float authors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + -------------------------------------------------------------------------------- ## FreeType (www.freetype.org) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20306635..9dfd00b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ ## Newest Release +### 4.0.0 - 01 Nov 2024 + +- Adds Pigeon for communication between Flutter and native iOS and Android platforms. (J#HYB-455) +- Fixes issue where annotation preset configurations are not applied to some annotation tools. (J#HYB-185) +- Fixes inconsistency in the `applyInstantJson` method parameter type. It now accepts a string on both iOS and Android. (#45541) +- Updates for Nutrient Android SDK 2024.6.1. (#45458) +- Updates for Nutrient iOS SDK 14.1.1. (#45458) +- Updates for Nutrient Web SDK 2024.7.0. (#45458) + +## Previous Releases + +### 3.12.0 - 30 Jul 2024 + ### 3.12.1 - 11 Sep 2024 - Updates for PSPDFKit 2024.5.1 for Android. (J#HYB-506) @@ -8,8 +21,6 @@ - Fixes an issue where some annotation toolbar items are not displayed when custom grouping is used. (J#HYB-440) - Fixes an issue where `onDocumentLoaded` is triggered multiple times. (J#HYB-494) -## Previous Releases - ### 3.12.0 - 30 Jul 2024 - Adds `zoomToRect` and `getVisibleRect` APIs to `PspdfkitWidgetController`. (J#HYB-429) diff --git a/README.md b/README.md index 1f02f0cb..cf67643f 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,22 @@ -# Flutter PDF Library by PSPDFKit +# Flutter PDF Library by Nutrient -![Flutter Intro](screenshots/flutter-intro.png) +![Flutter Intro](screenshots/flutter.png) -PSPDFKit for Flutter is an SDK for viewing, annotating, and editing PDFs. It offers developers the ability to quickly add PDF functionality to any Flutter application. It is available at [pub.dev](https://pub.dev/packages/pspdfkit_flutter) and [GitHub](https://github.com/PSPDFKit/pspdfkit-flutter). +Nutrient Flutter SDK is for viewing, annotating, and editing PDFs. It offers developers the ability to quickly add PDF functionality to any Flutter application. It is available at [pub.dev][pub_dev] and [GitHub][github]. If you are new to Flutter, make sure to check our Flutter blog posts: -- [How I Got Started With Flutter](https://pspdfkit.com/blog/2018/starting-with-flutter/). -- [Getting Started with Flutter PDF Library by PSPDFKit](https://pspdfkit.com/blog/2019/getting-started-with-pspdfkit-flutter/). -- [Opening a PDF in Flutter](https://pspdfkit.com/blog/2019/opening-a-pdf-in-flutter/). -- [How to Bridge Native iOS Code to Flutter](https://pspdfkit.com/blog/2021/how-to-bridge-native-ios-code-to-flutter/). -- [How to Customize Our Flutter PDF SDK for Android](https://pspdfkit.com/blog/2021/how-to-customize-our-flutter-pdf-sdk/). -- [Advances in Hybrid Technologies](https://pspdfkit.com/blog/2019/advances-in-hybrid-technologies/). -- [How We Maintain Our Public Flutter Project Using a Private Monorepo](https://pspdfkit.com/blog/2021/maintaining-open-source-repo-from-monorepo/). -- [How to Download and Display a PDF Document in Flutter with PSPDFKit](https://pspdfkit.com/blog/2022/download-and-display-pdf-in-flutter-with-pspdfkit/). +- [Getting Started with Flutter PDF Library by Nutrient][blog_getting_started_with_pspdfkit_flutter]. +- [Opening a PDF in Flutter][blog_opening_a_pdf_in_flutter]. +- [How to Customize Our Flutter PDF SDK][blog_customize_flutter_pdf_sdk_android]. +- [Advances in Hybrid Technologies][blog_advances_in_hybrid_technologies]. +- [How We Maintain Our Public Flutter Project Using a Private Monorepo][blog_maintaining_open_source_repo_from_monorepo]. +- [How to Download and Display a PDF Document in Flutter with Nutrient][blog_download_display_pdf_in_flutter_with_pspdfkit]. -For our quick-start guides, [check out our website](https://pspdfkit.com/getting-started/mobile/?frontend=flutter). +For our quick-start guides, [check out our website][quick_start_guides]. + +Platform specific README exists for [Android][android_readme] and [iOS][ios_readme]. -Platform specific README exists for [Android](android/) and [iOS](ios/). # Setup @@ -153,7 +152,7 @@ Platform specific README exists for [Android](android/) and [iOS](ios/). - jvmTarget = '1.8' + jvmTarget = '17' } - ... + ... } ``` 6. Add the AppCompat AndroidX library to your `android/app/build.gradle` file: @@ -184,14 +183,14 @@ Platform specific README exists for [Android](android/) and [iOS](ios/). Alternatively you can update the `AndroidManifest.xml` file to use `FlutterAppCompatActivity` as the launcher activity: ```diff - ``` **NOTE:** FlutterAppCompatActivity isn’t an official part of the Flutter SDK. It’s a custom Activity that extends AppCompatActivity from the AndroidX AppCompat library, and it’s necessary to use PSPDFKit for Android with Flutter. You can read more about this in the [AppCompatActivity Migration][] guide. @@ -287,7 +286,7 @@ Platform specific README exists for [Android](android/) and [iOS](ios/). PSPDFKit for Web library files are distributed as an archive that can be extracted manually. -1. Download the framework here. The download will start immediately and will save a `.tar.gz` archive like `PSPDFKit-Web-binary-<%= latest_version(:web) %>.tar.gz` to your computer. +1. Download the framework here. The download will start immediately and will save a `.tar.gz` archive like `PSPDFKit-Web-binary-<%= latest_version(:web) %>.tar.gz` to your computer. 2. Once the download is complete, extract the archive and copy the **entire** contents of its `dist` folder to your project’s `web/assets` folder or any other folder of your choice inside the web subfolder. @@ -312,49 +311,50 @@ To see PSPDFKit for Flutter in action check out our [Flutter example app](exampl Showing a PDF document inside your Flutter app is as simple as this: - ```dart +```dart PspdfkitWidget(documentPath: 'file:///path/to/Documentpdf') - ``` +``` -# Upgrading to a Full PSPDFKit License Key +# Upgrading to a Full Nutrient License Key -PSPDFKit is a commercial product and requires the purchase of a license key when used in production. By default, this library will -initialize in demo mode, placing a watermark on each PDF and limiting usage to 60 minutes. +Nutrient is a commercial product and requires the purchase of a license key when used in production. By default, this library will initialize in demo mode, placing a watermark on each PDF and limiting usage to 60 minutes. -To purchase a license for production use, please reach out to us via https://pspdfkit.com/sales/form/. +To purchase a license for production use, please reach out to us via [contact_sales]. -To initialize PSPDFKit using a license key, call either of the following before using any other PSPDFKit APIs or features: +To initialize Nutrient using a license key, call either of the following before using any other Nutrient APIs or features: To set the license key for both Android and iOS, use: -``` -await Pspdfkit.setLicenseKeys("YOUR_FLUTTER_ANDROID_LICENSE_KEY_GOES_HERE", "YOUR_FLUTTER_IOS_LICENSE_KEY_GOES_HERE"); -``` - -To set the license key for the currently running platform, use: -``` -await Pspdfkit.setLicenseKey("YOUR_FLUTTER_LICENSE_KEY_GOES_HERE"); +```dart +await Pspdfkit.initialize( + androidLicenseKey:"YOUR_FLUTTER_ANDROID_LICENSE_KEY_GOES_HERE", + iosLicenseKey:"YOUR_FLUTTER_IOS_LICENSE_KEY_GOES_HERE", + webLicenseKey: "YOUR_FLUTTER_WEB_LICENSE_KEY_GOES_HERE" + ); ``` # Migrating from Previous Version -To upgrade PSPDFKit for Flutter in your app, please refer to the [Upgrade and Migration Guides][flutter upgrade] section. +To upgrade Nutrient for Flutter in your app, please refer to the [Upgrade and Migration Guides][flutter_upgrade] section. # Troubleshooting -For Troubleshooting common issues you might encounter when setting up PSPDFKit for Flutter, please refer to the [Troubleshooting][] section. - +For Troubleshooting common issues you might encounter when setting up Nutrient for Flutter, please refer to the [Troubleshooting][troubleshooting] section. -[install-flutter]: https://flutter.dev/docs/get-started/install -[android studio]: https://developer.android.com/studio -[install ndk]: https://developer.android.com/studio/projects/install-ndk -[managing avds]: https://developer.android.com/studio/run/managing-avds.html -[xcode]: https://apps.apple.com/us/app/xcode/id497799835?mt=12 -[cocoapods releases]: https://github.com/CocoaPods/CocoaPods/releases -[start-the-emulator]: https://developer.android.com/studio/run/emulator#runningemulator -[flutter upgrade]: https://pspdfkit.com/guides/flutter/upgrade/ -[troubleshooting]: https://pspdfkit.com/guides/flutter/troubleshoot/ -[appcompatactivity migration]: https://pspdfkit.com/guides/flutter/troubleshooting/pspdfkit-widget-appcompat-activity-issue/ -[appearance styling]: /guides/android/customizing-the-interface/appearance-styling -[chrome]: https://www.google.com/chrome/ \ No newline at end of file +[pub_dev]: https://pub.dev/packages/pspdfkit_flutter +[github]: https://github.com/PSPDFKit/pspdfkit-flutter +[blog_starting_with_flutter]: https://nutrient.io/blog/2018/starting-with-flutter/ +[blog_getting_started_with_pspdfkit_flutter]: https://nutrient.io/blog/getting-started-with-pspdfkit-flutter/ +[blog_opening_a_pdf_in_flutter]: https://nutrient.io/blog/opening-a-pdf-in-flutter/ +[blog_customize_flutter_pdf_sdk_android]: https://www.nutrient.io/guides/flutter/customize/? +[blog_advances_in_hybrid_technologies]: https://nutrient.io/blog/advances-in-hybrid-technologies/ +[blog_maintaining_open_source_repo_from_monorepo]: https://nutrient.io/blog/maintaining-open-source-repo-from-monorepo/ +[blog_download_display_pdf_in_flutter_with_pspdfkit]: https://nutrient.io/blog/download-and-display-pdf-in-flutter-with-pspdfkit/ +[quick_start_guides]: https://nutrient.io/getting-started/mobile/?frontend=flutter +[android_readme]: android/ +[ios_readme]: ios/ +[contact_sales]: https://nutrient.io/sdk/contact-sales +[flutter_upgrade]: https://nutrient.io/guides/flutter/upgrade/ +[troubleshooting]: https://nutrient.io/guides/flutter/troubleshoot/ +[appcompatactivity_migration]: https://nutrient.io/guides/flutter/troubleshooting/pspdfkit-widget-appcompat-activity-issue/ diff --git a/android/build.gradle b/android/build.gradle index 7bff0f83..f3d2ef92 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -56,14 +56,14 @@ android { } dependencies { - implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.appcompat:appcompat:1.7.0' implementation "com.pspdfkit:$pspdfkitMavenModuleName:$pspdfkitVersion" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation "androidx.compose.material:material:1.6.5" - implementation "androidx.compose.material:material:1.6.3" - implementation "androidx.constraintlayout:constraintlayout:2.1.4" - implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1" - implementation "androidx.compose.foundation:foundation:1.6.3" - implementation "androidx.compose.ui:ui:1.6.3" + implementation "androidx.compose.material:material:1.7.5" + implementation "androidx.compose.material:material:1.7.5" + implementation "androidx.constraintlayout:constraintlayout:2.2.0" + implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0" + implementation "androidx.compose.foundation:foundation:1.7.5" + implementation "androidx.compose.ui:ui:1.7.5" } diff --git a/android/config.gradle b/android/config.gradle index 92d57f5b..d26dd6ed 100644 --- a/android/config.gradle +++ b/android/config.gradle @@ -38,7 +38,7 @@ if (pspdfkitMavenUrl == null || pspdfkitMavenUrl == '') { ext.pspdfkitVersion = localProperties.getProperty('pspdfkit.version') if (pspdfkitVersion == null || pspdfkitVersion == '') { - ext.pspdfkitVersion = '2024.5.1' + ext.pspdfkitVersion = '2024.6.1' } ext.pspdfkitMavenModuleName = 'pspdfkit' diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/AnnotationConfigurationAdaptor.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/AnnotationConfigurationAdaptor.kt index 3c77b32c..7ad436bd 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/AnnotationConfigurationAdaptor.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/AnnotationConfigurationAdaptor.kt @@ -48,9 +48,11 @@ import com.pspdfkit.annotations.configuration.SoundAnnotationConfiguration import com.pspdfkit.annotations.configuration.StampAnnotationConfiguration import com.pspdfkit.annotations.stamps.StampPickerItem import com.pspdfkit.configuration.annotations.AnnotationAggregationStrategy +import com.pspdfkit.flutter.pspdfkit.annotations.FlutterAnnotationPresetConfiguration import com.pspdfkit.ui.fonts.Font import com.pspdfkit.ui.inspector.views.BorderStylePreset import com.pspdfkit.ui.special_mode.controller.AnnotationTool +import com.pspdfkit.ui.special_mode.controller.AnnotationToolVariant import java.util.EnumSet const val DEFAULT_COLOR = "color" @@ -120,12 +122,12 @@ class AnnotationConfigurationAdaptor { companion object { - private val configurations = mutableMapOf() + private val configurationsList:MutableList = mutableListOf() @JvmStatic fun convertAnnotationConfigurations( context: Context, annotationConfigurations: Map<*, *> - ): Map { + ): List { val iterator = annotationConfigurations.keys.iterator() @@ -134,158 +136,115 @@ class AnnotationConfigurationAdaptor { val configuration = (annotationConfigurations[key] as Map<*, *>?) ?: continue when (key) { ANNOTATION_INK_PEN -> { - configurations[INK] = - parseInkAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(INK, AnnotationTool.INK, AnnotationToolVariant.fromPreset(AnnotationToolVariant.Preset.PEN), parseInkAnnotationConfiguration(context, configuration))) } ANNOTATION_INK_HIGHLIGHTER -> { - configurations[AnnotationTool.INK.toAnnotationType()] = - parseInkAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(INK, AnnotationTool.INK, AnnotationToolVariant.fromPreset(AnnotationToolVariant.Preset.HIGHLIGHTER), parseInkAnnotationConfiguration(context, configuration))) } ANNOTATION_INK_MAGIC -> { - configurations[AnnotationTool.MAGIC_INK.toAnnotationType()] = - parseInkAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(INK, AnnotationTool.MAGIC_INK, AnnotationToolVariant.fromPreset(AnnotationToolVariant.Preset.MAGIC), parseInkAnnotationConfiguration(context, configuration))) } ANNOTATION_UNDERLINE -> { - configurations[UNDERLINE] = - parseMarkupAnnotationConfiguration(context, configuration, UNDERLINE) + configurationsList.add(FlutterAnnotationPresetConfiguration(UNDERLINE, AnnotationTool.UNDERLINE, null, parseMarkupAnnotationConfiguration(context, configuration, UNDERLINE))) } ANNOTATION_FREE_TEXT -> { - configurations[FREETEXT] = - parserFreeTextAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(FREETEXT, AnnotationTool.FREETEXT, null, parserFreeTextAnnotationConfiguration(context, configuration))) } ANNOTATION_LINE -> { - configurations[LINE] = - parseLineAnnotationConfiguration( - context, - configuration, - LINE, - AnnotationTool.LINE - ) + configurationsList.add(FlutterAnnotationPresetConfiguration(LINE, AnnotationTool.LINE, null, parseLineAnnotationConfiguration(context, configuration, LINE, AnnotationTool.LINE))) } ANNOTATION_NOTE -> { - configurations[NOTE] = - parseNoteAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(NOTE, AnnotationTool.NOTE, null, parseNoteAnnotationConfiguration(context, configuration))) } ANNOTATION_STAMP -> { - configurations[STAMP] = - parseStampAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(STAMP, AnnotationTool.STAMP, null, parseStampAnnotationConfiguration(context, configuration))) } ANNOTATION_FILE -> { - configurations[FILE] = - parseFileAnnotationConfiguration(configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(FILE, null, null, parseFileAnnotationConfiguration(configuration))) } ANNOTATION_REDACTION -> { - configurations[REDACT] = - parseRedactAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(REDACT, null, null, parseRedactAnnotationConfiguration(context, configuration))) } ANNOTATION_SOUND -> { - configurations[SOUND] = - parseSoundAnnotationConfiguration(configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(SOUND, null, null, parseSoundAnnotationConfiguration(configuration))) } ANNOTATION_HIGHLIGHT -> { - configurations[HIGHLIGHT] = - parseMarkupAnnotationConfiguration(context, configuration, HIGHLIGHT) + configurationsList.add(FlutterAnnotationPresetConfiguration(HIGHLIGHT, AnnotationTool.HIGHLIGHT,null, parseMarkupAnnotationConfiguration(context, configuration, HIGHLIGHT))) } ANNOTATION_SQUARE -> { - configurations[SQUARE] = - parseShapeAnnotationConfiguration(context, configuration, SQUARE) + configurationsList.add(FlutterAnnotationPresetConfiguration(SQUARE, AnnotationTool.SQUARE, null, parseShapeAnnotationConfiguration(context, configuration, SQUARE))) } ANNOTATION_CIRCLE -> { - configurations[CIRCLE] = - parseShapeAnnotationConfiguration(context, configuration, CIRCLE) + configurationsList.add(FlutterAnnotationPresetConfiguration(CIRCLE, AnnotationTool.CIRCLE, null, parseShapeAnnotationConfiguration(context, configuration, CIRCLE))) } ANNOTATION_POLYGON -> { - configurations[POLYGON] = - parseShapeAnnotationConfiguration(context, configuration, POLYGON) + configurationsList.add(FlutterAnnotationPresetConfiguration(POLYGON, AnnotationTool.POLYGON, null, parseShapeAnnotationConfiguration(context, configuration, POLYGON))) } ANNOTATION_POLYLINE -> { - configurations[POLYLINE] = - parseLineAnnotationConfiguration( - context, - configuration, - POLYLINE, - AnnotationTool.POLYLINE - ) + configurationsList.add(FlutterAnnotationPresetConfiguration(POLYLINE, AnnotationTool.POLYLINE, null, parseLineAnnotationConfiguration(context, configuration, POLYLINE, AnnotationTool.POLYLINE))) } ANNOTATION_IMAGE -> { - configurations[AnnotationTool.IMAGE.toAnnotationType()] = - parseStampAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(STAMP, AnnotationTool.IMAGE, null, parseStampAnnotationConfiguration(context, configuration))) } ANNOTATION_ARROW -> { - configurations[LINE] = - parseLineAnnotationConfiguration( - context, - configuration, - LINE, - AnnotationTool.LINE - ) + configurationsList.add(FlutterAnnotationPresetConfiguration(LINE, AnnotationTool.LINE, AnnotationToolVariant.fromPreset(AnnotationToolVariant.Preset.ARROW), parseLineAnnotationConfiguration(context, configuration, LINE, AnnotationTool.LINE))) } ANNOTATION_SQUIGGLY -> { - configurations[SQUIGGLY] = - parseMarkupAnnotationConfiguration(context, configuration, SQUIGGLY) + configurationsList.add(FlutterAnnotationPresetConfiguration(SQUIGGLY, AnnotationTool.SQUIGGLY, null, parseMarkupAnnotationConfiguration(context, configuration, SQUIGGLY))) } ANNOTATION_STRIKE_OUT -> { - configurations[STRIKEOUT] = - parseMarkupAnnotationConfiguration(context, configuration, STRIKEOUT) + configurationsList.add(FlutterAnnotationPresetConfiguration(STRIKEOUT, AnnotationTool.STRIKEOUT, null, parseMarkupAnnotationConfiguration(context, configuration, STRIKEOUT))) } ANNOTATION_ERASER -> { - configurations[AnnotationTool.ERASER.toAnnotationType()] = - parseEraserAnnotationConfiguration(configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(null, AnnotationTool.ERASER, null, parseEraserAnnotationConfiguration(configuration))) } ANNOTATION_AUDIO -> { - configurations[SOUND] = - parseSoundAnnotationConfiguration(configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(SOUND, null, null, parseSoundAnnotationConfiguration(configuration))) } ANNOTATION_FREE_TEXT_CALL_OUT -> { - configurations[AnnotationTool.FREETEXT_CALLOUT.toAnnotationType()] = - parserFreeTextAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(FREETEXT, AnnotationTool.FREETEXT_CALLOUT, null, parserFreeTextAnnotationConfiguration(context, configuration))) } ANNOTATION_MEASUREMENT_AREA_RECT -> { - configurations[AnnotationTool.MEASUREMENT_AREA_RECT.toAnnotationType()] = - parserMeasurementAreaAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(null, AnnotationTool.MEASUREMENT_AREA_RECT, null, parserMeasurementAreaAnnotationConfiguration(context, configuration))) } ANNOTATION_MEASUREMENT_AREA_POLYGON -> { - configurations[AnnotationTool.MEASUREMENT_AREA_POLYGON.toAnnotationType()] = - parserMeasurementAreaAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(null, AnnotationTool.MEASUREMENT_AREA_POLYGON, null, parserMeasurementAreaAnnotationConfiguration(context, configuration))) } ANNOTATION_MEASUREMENT_AREA_ELLIPSE -> { - configurations[AnnotationTool.MEASUREMENT_AREA_ELLIPSE.toAnnotationType()] = - parserMeasurementAreaAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(null, AnnotationTool.MEASUREMENT_AREA_ELLIPSE, null, parserMeasurementAreaAnnotationConfiguration(context, configuration))) } ANNOTATION_MEASUREMENT_PERIMETER -> { - configurations[AnnotationTool.MEASUREMENT_PERIMETER.toAnnotationType()] = - parseMeasurementPerimeterAnnotationConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(null, AnnotationTool.MEASUREMENT_PERIMETER, null, parseMeasurementPerimeterAnnotationConfiguration(context, configuration))) } ANNOTATION_MEASUREMENT_DISTANCE -> { - configurations[AnnotationTool.MEASUREMENT_DISTANCE.toAnnotationType()] = - parseMeasurementDistanceConfiguration(context, configuration) + configurationsList.add(FlutterAnnotationPresetConfiguration(null, AnnotationTool.MEASUREMENT_DISTANCE, null, parseMeasurementDistanceConfiguration(context, configuration))) } else -> { @@ -293,7 +252,7 @@ class AnnotationConfigurationAdaptor { } } } - return configurations + return configurationsList } private fun parserMeasurementAreaAnnotationConfiguration( diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/EventDispatcher.java b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/EventDispatcher.java index bcbc5bc4..5edff714 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/EventDispatcher.java +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/EventDispatcher.java @@ -11,19 +11,16 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; - import com.pspdfkit.document.PdfDocument; - import org.jetbrains.annotations.NotNull; - import java.util.HashMap; - import io.flutter.plugin.common.MethodChannel; /** * Internal singleton class used to communicate between activities and the PSPDFKit Flutter plugin. */ public class EventDispatcher { + @Nullable private static EventDispatcher instance; /** @@ -33,8 +30,8 @@ public class EventDispatcher { @Nullable private MethodChannel channel = null; - private EventDispatcher() { - } + @Nullable + private PspdfkitApiCallbacks pspdfkitApiCallbacks; @NonNull public static synchronized EventDispatcher getInstance() { @@ -48,20 +45,37 @@ public void setChannel(@Nullable MethodChannel channel) { this.channel = channel; } + public void setPspdfkitApiCallbacks(@Nullable PspdfkitApiCallbacks pspdfkitApiCallbacks) { + this.pspdfkitApiCallbacks = pspdfkitApiCallbacks; + } + public void notifyActivityOnPause() { sendEvent("flutterPdfActivityOnPause"); + + if (pspdfkitApiCallbacks != null) { + pspdfkitApiCallbacks.onActivityPaused(); + } } public void notifyPdfFragmentAdded() { sendEvent("flutterPdfFragmentAdded"); + if (pspdfkitApiCallbacks != null) { + pspdfkitApiCallbacks.onFragmentAttached(); + } } public void notifyInstantSyncStarted(String documentId) { sendEvent("pspdfkitInstantSyncStarted", documentId); + if (pspdfkitApiCallbacks != null) { + pspdfkitApiCallbacks.onSyncStarted(documentId); + } } public void notifyInstantSyncFinished(String documentId) { sendEvent("pspdfkitInstantSyncFinished", documentId); + if (pspdfkitApiCallbacks != null) { + pspdfkitApiCallbacks.onSyncFinished(documentId); + } } public void notifyInstantSyncFailed(String documentId, String error) { @@ -69,6 +83,10 @@ public void notifyInstantSyncFailed(String documentId, String error) { put("documentId", documentId); put("error", error); }}); + + if (pspdfkitApiCallbacks != null) { + pspdfkitApiCallbacks.onSyncError(documentId, error); + } } public void notifyInstantAuthenticationFinished(String documentId,String validJWT) { @@ -76,6 +94,10 @@ public void notifyInstantAuthenticationFinished(String documentId,String validJW put("documentId", documentId); put("jwt", validJWT); }}); + + if (pspdfkitApiCallbacks != null) { + pspdfkitApiCallbacks.onAuthenticationFinished(documentId, validJWT); + } } public void notifyInstantAuthenticationFailed(String documentId, String error) { @@ -83,6 +105,10 @@ public void notifyInstantAuthenticationFailed(String documentId, String error) { put("documentId", documentId); put("error", error); }}); + + if (pspdfkitApiCallbacks != null) { + pspdfkitApiCallbacks.onAuthenticationFailed(documentId, error); + } } private void sendEvent(String eventName) { @@ -97,5 +123,8 @@ private void sendEvent(@NonNull final String method, @Nullable final Object argu public void notifyDocumentLoaded(@NotNull PdfDocument document) { sendEvent("pspdfkitDocumentLoaded", document.getUid()); + if (pspdfkitApiCallbacks != null) { + pspdfkitApiCallbacks.onDocumentLoaded(document.getUid()); + } } } diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterInstantPdfActivity.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterInstantPdfActivity.kt index 1f9f853b..234ef51c 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterInstantPdfActivity.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterInstantPdfActivity.kt @@ -1,14 +1,16 @@ -package com.pspdfkit.flutter.pspdfkit +/* + * Copyright © 2021-2024 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. + */ -/// Copyright © 2021-2024 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. -/// +package com.pspdfkit.flutter.pspdfkit import android.os.Bundle +import androidx.fragment.app.Fragment import com.pspdfkit.document.PdfDocument import com.pspdfkit.flutter.pspdfkit.util.MeasurementHelper import com.pspdfkit.instant.document.InstantPdfDocument @@ -24,8 +26,8 @@ import java.util.concurrent.atomic.AtomicReference class FlutterInstantPdfActivity : InstantPdfActivity() { - override fun onCreate(bundle: Bundle?) { - super.onCreate(bundle) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) bindActivity() } @@ -96,6 +98,13 @@ class FlutterInstantPdfActivity : InstantPdfActivity() { ) } + override fun onAttachFragment(fragment: Fragment) { + super.onAttachFragment(fragment) + if(fragment.tag?.contains("PSPDFKit.Fragment") == true){ + EventDispatcher.getInstance().notifyPdfFragmentAdded() + } + } + private fun bindActivity() { currentActivity = this } @@ -125,6 +134,4 @@ class FlutterInstantPdfActivity : InstantPdfActivity() { measurementValueConfigurations = configurations } } - - } \ No newline at end of file diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfActivity.java b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfActivity.java index 0989ca8b..27bcf5b8 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfActivity.java +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfActivity.java @@ -1,9 +1,19 @@ +/* + * Copyright © 2018-2024 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. + */ + package com.pspdfkit.flutter.pspdfkit; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; import com.pspdfkit.document.PdfDocument; import com.pspdfkit.flutter.pspdfkit.util.MeasurementHelper; @@ -64,6 +74,15 @@ public void onDocumentLoaded(@NonNull PdfDocument pdfDocument) { MeasurementHelper.addMeasurementConfiguration(getPdfFragment(), configuration); } } + EventDispatcher.getInstance().notifyDocumentLoaded(pdfDocument); + } + + @Override + public void onAttachFragment(@NonNull Fragment fragment) { + super.onAttachFragment(fragment); + if(fragment.getTag() !=null && fragment.getTag().contains("PSPDFKit.Fragment")){ + EventDispatcher.getInstance().notifyPdfFragmentAdded(); + } } @Override diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragment.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragment.kt index cb20af80..678b71dd 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragment.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragment.kt @@ -1,7 +1,22 @@ +/* + * Copyright © 2018-2024 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. + */ + package com.pspdfkit.flutter.pspdfkit +/// Copyright © 2021-2024 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 com.pspdfkit.document.PdfDocument -import com.pspdfkit.flutter.pspdfkit.util.MeasurementHelper import com.pspdfkit.ui.PdfUiFragment class FlutterPdfUiFragment : PdfUiFragment() { diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragmentCallbacks.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragmentCallbacks.kt index ab8a8157..946d33d6 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragmentCallbacks.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragmentCallbacks.kt @@ -1,9 +1,25 @@ +/* + * Copyright © 2024 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. + */ package com.pspdfkit.flutter.pspdfkit +/// Copyright © 2024 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 android.content.Context import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import com.pspdfkit.document.PdfDocument +import com.pspdfkit.flutter.pspdfkit.api.PdfDocumentApi import com.pspdfkit.flutter.pspdfkit.document.FlutterPdfDocument import com.pspdfkit.flutter.pspdfkit.util.MeasurementHelper import com.pspdfkit.listeners.DocumentListener @@ -11,10 +27,20 @@ import com.pspdfkit.ui.PdfFragment import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.MethodChannel +/** + * Callbacks for the FlutterPdfUiFragment. + * This class is responsible for notifying the Flutter side about document loading events. + * It also sets up the PdfDocumentApi for the FlutterPdfDocument. + * @param methodChannel The method channel to communicate with the Flutter side. + * @param measurementConfigurations The measurement configurations to apply to the PdfFragment. + * @param binaryMessenger The binary messenger to communicate with the Flutter side. + * @param flutterWidgetCallback The callback to notify the Flutter side about document loading events. + */ class FlutterPdfUiFragmentCallbacks( private val methodChannel: MethodChannel, private val measurementConfigurations: List>?, - private val binaryMessenger: BinaryMessenger + private val binaryMessenger: BinaryMessenger, + private val flutterWidgetCallback: FlutterWidgetCallback ) : FragmentManager.FragmentLifecycleCallbacks(), DocumentListener { private var pdfFragment: PdfFragment? = null @@ -33,7 +59,7 @@ class FlutterPdfUiFragmentCallbacks( if (pdfFragment != null) { return } - pdfFragment = f as PdfFragment + pdfFragment = f pdfFragment?.addDocumentListener(this) } } @@ -47,13 +73,15 @@ class FlutterPdfUiFragmentCallbacks( "documentId" to document.uid ) ) - + flutterWidgetCallback.onDocumentLoaded(document) flutterPdfDocument = - FlutterPdfDocument(document, binaryMessenger); + FlutterPdfDocument(document); + PdfDocumentApi.setUp(binaryMessenger, flutterPdfDocument, document.uid) } override fun onPageChanged(document: PdfDocument, pageIndex: Int) { super.onPageChanged(document, pageIndex) + flutterWidgetCallback.onPageChanged(document, pageIndex) methodChannel.invokeMethod( "onPageChanged", mapOf( @@ -65,6 +93,7 @@ class FlutterPdfUiFragmentCallbacks( override fun onDocumentLoadFailed(exception: Throwable) { super.onDocumentLoadFailed(exception) + flutterWidgetCallback.onDocumentLoadFailed(exception) methodChannel.invokeMethod( "onDocumentLoadFailed", mapOf( diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterWidgetCallback.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterWidgetCallback.kt new file mode 100644 index 00000000..b20a8641 --- /dev/null +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterWidgetCallback.kt @@ -0,0 +1,39 @@ +/* + * Copyright © 2024 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. + */ + +package com.pspdfkit.flutter.pspdfkit + +import com.pspdfkit.document.PdfDocument +import com.pspdfkit.flutter.pspdfkit.api.PspdfkitWidgetCallbacks +import com.pspdfkit.listeners.DocumentListener + + +class FlutterWidgetCallback( + private var pspdfkitWidgetCallbacks: PspdfkitWidgetCallbacks? = null +) : DocumentListener { + + override fun onDocumentLoaded(document: PdfDocument) { + pspdfkitWidgetCallbacks?.onDocumentLoaded(document.uid) {} + super.onDocumentLoaded(document) + } + + override fun onPageChanged(document: PdfDocument, pageIndex: Int) { + super.onPageChanged(document, pageIndex) + pspdfkitWidgetCallbacks?.onPageChanged(document.uid, pageIndex.toLong()) { + } + } + + override fun onDocumentLoadFailed(exception: Throwable) { + pspdfkitWidgetCallbacks?.onDocumentError( + "", + exception.localizedMessage ?: "Error while loading document!" + ) {} + super.onDocumentLoadFailed(exception) + } +} \ No newline at end of file diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PSPDFKitView.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PSPDFKitView.kt index 9588256b..d630d8e6 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PSPDFKitView.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PSPDFKitView.kt @@ -1,5 +1,12 @@ +/* + * Copyright © 2018-2024 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. + */ package com.pspdfkit.flutter.pspdfkit - import android.annotation.SuppressLint import android.content.Context import android.content.MutableContextWrapper @@ -19,6 +26,8 @@ import com.pspdfkit.document.processor.PdfProcessor import com.pspdfkit.document.processor.PdfProcessor.ProcessorProgress import com.pspdfkit.document.processor.PdfProcessorTask import com.pspdfkit.flutter.pspdfkit.AnnotationConfigurationAdaptor.Companion.convertAnnotationConfigurations +import com.pspdfkit.flutter.pspdfkit.api.PspdfkitWidgetCallbacks +import com.pspdfkit.flutter.pspdfkit.api.PspdfkitWidgetControllerApi import com.pspdfkit.flutter.pspdfkit.toolbar.FlutterMenuGroupingRule import com.pspdfkit.flutter.pspdfkit.toolbar.FlutterViewModeController import com.pspdfkit.flutter.pspdfkit.util.DocumentJsonDataProvider @@ -50,8 +59,8 @@ import java.io.File internal class PSPDFKitView( val context: Context, - id: Int, - messenger: BinaryMessenger, + private val id: Int, + private val messenger: BinaryMessenger, documentPath: String? = null, configurationMap: HashMap? = null, ) : PlatformView, MethodCallHandler { @@ -60,7 +69,10 @@ internal class PSPDFKitView( private val methodChannel: MethodChannel private val pdfUiFragment: PdfUiFragment private var fragmentCallbacks: FlutterPdfUiFragmentCallbacks? = null - + private val pspdfkitViewImpl: PspdfkitViewImpl = PspdfkitViewImpl() + private val widgetCallbacks: PspdfkitWidgetCallbacks = + PspdfkitWidgetCallbacks(messenger, "widget.callbacks.$id") + init { fragmentContainerView?.id = View.generateViewId() methodChannel = MethodChannel(messenger, "com.pspdfkit.widget.$id") @@ -93,11 +105,13 @@ internal class PSPDFKitView( .build() } } - fragmentCallbacks = FlutterPdfUiFragmentCallbacks(methodChannel, - measurementValueConfigurations, messenger) + + fragmentCallbacks = FlutterPdfUiFragmentCallbacks(methodChannel, measurementValueConfigurations, messenger,FlutterWidgetCallback(widgetCallbacks)) + fragmentCallbacks?.let { getFragmentActivity(context).supportFragmentManager.registerFragmentLifecycleCallbacks(it, true) } + getFragmentActivity(context).supportFragmentManager.registerFragmentLifecycleCallbacks( object : FragmentManager.FragmentLifecycleCallbacks() { override fun onFragmentAttached( fm: FragmentManager, @@ -119,6 +133,7 @@ internal class PSPDFKitView( override fun onViewAttachedToWindow(view: View) { getFragmentActivity(context).supportFragmentManager.commitNow { add(it.id, pdfUiFragment) + pspdfkitViewImpl.setPdfFragment(pdfUiFragment) setReorderingAllowed(true) } } @@ -126,6 +141,7 @@ internal class PSPDFKitView( override fun onViewDetachedFromWindow(view: View) { getFragmentActivity(context).supportFragmentManager.commit { remove(pdfUiFragment) + pspdfkitViewImpl.setPdfFragment(null) setReorderingAllowed(true) } } @@ -140,12 +156,24 @@ internal class PSPDFKitView( override fun dispose() { fragmentContainerView = null + // Unregister method channel. + PspdfkitWidgetControllerApi.setUp(messenger, null, id.toString()) + pspdfkitViewImpl.dispose() + pspdfkitViewImpl.setPdfFragment(null) fragmentCallbacks?.let { - getFragmentActivity(context).supportFragmentManager.unregisterFragmentLifecycleCallbacks(it) + getFragmentActivity(context).supportFragmentManager.unregisterFragmentLifecycleCallbacks( + it, + ) } fragmentCallbacks = null } + override fun onFlutterViewAttached(flutterView: View) { + super.onFlutterViewAttached(flutterView) + // Set up the method channel for communication with Flutter. + PspdfkitWidgetControllerApi.setUp(messenger, pspdfkitViewImpl, id.toString()) + } + @SuppressLint("CheckResult") override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { // Return if the fragment or the document @@ -153,7 +181,7 @@ internal class PSPDFKitView( if (!pdfUiFragment.isAdded) { return } - var document = pdfUiFragment.document ?: return + val document = pdfUiFragment.document ?: return when (call.method) { "applyInstantJson" -> { @@ -432,7 +460,7 @@ internal class PSPDFKitView( .observeOn(AndroidSchedulers.mainThread()) .subscribe(result::success) } - "setAnnotationPresetConfigurations" -> { + "setAnnotationConfigurations" -> { try { val annotationConfigurations = call.argument>("annotationConfigurations") @@ -453,8 +481,26 @@ internal class PSPDFKitView( result.error("InvalidState", "PdfFragment is null", null) return } - for ((key, value) in configurations) { - pdfFragment.annotationConfiguration.put(key, value) + for (config in configurations) { + if (config.annotationTool != null && config.variant != null) { + pdfFragment.annotationConfiguration.put( + config.annotationTool, + config.variant, + config.configuration + ) + } + if (config.annotationTool != null && config.type == null) { + pdfFragment.annotationConfiguration.put( + config.annotationTool, + config.configuration + ) + } + if (config.type != null) { + pdfFragment.annotationConfiguration.put( + config.type, + config.configuration + ) + } } result.success(true) } catch (e: java.lang.Exception) { @@ -579,7 +625,6 @@ internal class PSPDFKitView( PdfProcessorTask.fromDocument(document) .changeAnnotationsOfType(annotationType, processingMode) } - PdfProcessor.processDocumentAsync(task, outputPath) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -627,7 +672,7 @@ class PSPDFKitViewFactory( private val messenger: BinaryMessenger, ) : PlatformViewFactory(StandardMessageCodec.INSTANCE) { override fun create(context: Context?, viewId: Int, args: Any?): PlatformView { - val creationParams = args as Map? + val creationParams = args as Map<*, *>? return PSPDFKitView( context!!, viewId, diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitApiCallbacks.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitApiCallbacks.kt new file mode 100644 index 00000000..c10a2fe9 --- /dev/null +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitApiCallbacks.kt @@ -0,0 +1,60 @@ +/* + * Copyright © 2024 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. + */ +package com.pspdfkit.flutter.pspdfkit + +import com.pspdfkit.flutter.pspdfkit.api.PspdfkitFlutterApiCallbacks + +/** + * Callbacks for the PspdfkitApi. This class is responsible for notifying the Flutter side about document loading events. + * A separate class is used because the callback methods are not supported by Java. + * @param pspdfkitFlutterApiCallbacks The callback to notify the Flutter side about document loading events. + */ +class PspdfkitApiCallbacks(private val pspdfkitFlutterApiCallbacks: PspdfkitFlutterApiCallbacks) { + + fun onDocumentLoaded(documentId: String) { + pspdfkitFlutterApiCallbacks.onDocumentLoaded(documentId) {} + } + + fun onSyncStarted(instantDocumentId: String) { + pspdfkitFlutterApiCallbacks.onInstantSyncStarted(instantDocumentId) {} + } + + fun onSyncFinished(instantDocumentId: String) { + pspdfkitFlutterApiCallbacks.onInstantSyncFinished(instantDocumentId) {} + } + + fun onAuthenticationFailed(instantDocumentId: String, error: String) { + pspdfkitFlutterApiCallbacks.onInstantAuthenticationFailed( + instantDocumentId, + error + ) {} + } + + fun onAuthenticationFinished(instantDocumentId: String, validJwt: String) { + pspdfkitFlutterApiCallbacks.onInstantAuthenticationFinished( + instantDocumentId, + validJwt + ) {} + } + + fun onSyncError(instantDocumentId: String, error: String) { + pspdfkitFlutterApiCallbacks.onInstantSyncFailed( + instantDocumentId, + error + ) {} + } + + fun onFragmentAttached() { + pspdfkitFlutterApiCallbacks.onPdfFragmentAdded {} + } + + fun onActivityPaused() { + pspdfkitFlutterApiCallbacks.onPdfActivityOnPause {} + } +} \ No newline at end of file diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitApiImpl.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitApiImpl.kt new file mode 100644 index 00000000..e61bbcf2 --- /dev/null +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitApiImpl.kt @@ -0,0 +1,822 @@ +/* + * Copyright © 2024 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. + */ +package com.pspdfkit.flutter.pspdfkit + +import android.Manifest +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.provider.Settings +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import androidx.fragment.app.FragmentActivity +import com.pspdfkit.PSPDFKit.VERSION +import com.pspdfkit.PSPDFKit.initialize +import com.pspdfkit.document.formatters.DocumentJsonFormatter +import com.pspdfkit.document.formatters.XfdfFormatter +import com.pspdfkit.document.html.HtmlToPdfConverter +import com.pspdfkit.document.processor.PdfProcessor +import com.pspdfkit.document.processor.PdfProcessor.ProcessorProgress +import com.pspdfkit.document.processor.PdfProcessorTask +import com.pspdfkit.exceptions.PSPDFKitException +import com.pspdfkit.flutter.pspdfkit.AnnotationConfigurationAdaptor.Companion.convertAnnotationConfigurations +import com.pspdfkit.flutter.pspdfkit.annotations.FlutterAnnotationPresetConfiguration +import com.pspdfkit.flutter.pspdfkit.api.AndroidPermissionStatus +import com.pspdfkit.flutter.pspdfkit.api.AnnotationProcessingMode +import com.pspdfkit.flutter.pspdfkit.api.PspdfkitApi +import com.pspdfkit.flutter.pspdfkit.api.PspdfkitApiError +import com.pspdfkit.flutter.pspdfkit.pdfgeneration.PdfPageAdaptor +import com.pspdfkit.flutter.pspdfkit.util.DocumentJsonDataProvider +import com.pspdfkit.flutter.pspdfkit.util.Preconditions +import com.pspdfkit.flutter.pspdfkit.util.ProcessorHelper.annotationTypeFromString +import com.pspdfkit.flutter.pspdfkit.util.ProcessorHelper.processModeFromString +import com.pspdfkit.flutter.pspdfkit.util.addFileSchemeIfMissing +import com.pspdfkit.flutter.pspdfkit.util.areValidIndexes +import com.pspdfkit.flutter.pspdfkit.util.isImageDocument +import com.pspdfkit.forms.ChoiceFormElement +import com.pspdfkit.forms.EditableButtonFormElement +import com.pspdfkit.forms.FormElement +import com.pspdfkit.forms.SignatureFormElement +import com.pspdfkit.forms.TextFormElement +import com.pspdfkit.initialization.CrossPlatformTechnology +import com.pspdfkit.initialization.InitializationOptions +import com.pspdfkit.instant.client.InstantProgress +import com.pspdfkit.instant.document.InstantPdfDocument +import com.pspdfkit.instant.ui.InstantPdfActivityIntentBuilder +import com.pspdfkit.preferences.PSPDFKitPreferences +import com.pspdfkit.ui.PdfActivity +import com.pspdfkit.ui.PdfActivityIntentBuilder +import com.pspdfkit.ui.special_mode.controller.AnnotationTool +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.disposables.Disposable +import io.reactivex.rxjava3.schedulers.Schedulers +import io.reactivex.rxjava3.subscribers.DisposableSubscriber +import java.io.ByteArrayOutputStream +import java.io.File +import java.io.FileOutputStream +import java.nio.charset.StandardCharsets + +class PspdfkitApiImpl(private var activityPluginBinding: ActivityPluginBinding?) : PspdfkitApi { + + private var disposable: Disposable? = null + + fun dispose() { + disposable?.dispose() + } + + fun setActivityPluginBinding(activityPluginBinding: ActivityPluginBinding?) { + this.activityPluginBinding = activityPluginBinding + } + + override fun getFrameworkVersion(callback: (Result) -> Unit) { + callback(Result.success(VERSION)) + } + + override fun setLicenseKey(licenseKey: String?, callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + setLicenseKey(activityPluginBinding?.activity as FragmentActivity, licenseKey) + callback(Result.success(Unit)) + } + + override fun setLicenseKeys( + androidLicenseKey: String?, + iOSLicenseKey: String?, + webLicenseKey: String?, + callback: (Result) -> Unit + ) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + setLicenseKey(activityPluginBinding?.activity as FragmentActivity, androidLicenseKey) + callback(Result.success(Unit)) + } + + override fun present( + document: String, configuration: Map?, callback: (Result) -> Unit + ) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + try { + var documentPath = document + documentPath = addFileSchemeIfMissing(documentPath) + val configurationMap = configuration as HashMap? + val configurationAdapter = ConfigurationAdapter( + activityPluginBinding?.activity as FragmentActivity, configurationMap + ) + val imageDocument = isImageDocument(documentPath) + val intent = if (imageDocument) { + PdfActivityIntentBuilder.fromImageUri( + activityPluginBinding?.activity as FragmentActivity, Uri.parse(documentPath) + ).activityClass(FlutterPdfActivity::class.java) + .configuration(configurationAdapter.build()).build() + } else { + PdfActivityIntentBuilder.fromUri( + activityPluginBinding?.activity as FragmentActivity, Uri.parse(documentPath) + ).activityClass(FlutterPdfActivity::class.java) + .configuration(configurationAdapter.build()) + .passwords(configurationAdapter.password).build() + } + activityPluginBinding?.activity?.startActivity(intent) + callback(Result.success(activityPluginBinding?.activity != null)) + } catch (e: PSPDFKitException) { + callback(Result.failure(PspdfkitApiError("Error", e.message))) + } + } + + override fun presentInstant( + serverUrl: String, + jwt: String, + configuration: Map?, + callback: (Result) -> Unit + ) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + try { + val configurationMapInstant = configuration as HashMap + val configurationAdapterInstant = ConfigurationAdapter( + activityPluginBinding?.activity as FragmentActivity, configurationMapInstant + ) + val annotationTools = + configurationAdapterInstant.build().configuration.enabledAnnotationTools + annotationTools.add(AnnotationTool.INSTANT_COMMENT_MARKER) + val intentInstant = InstantPdfActivityIntentBuilder.fromInstantDocument( + activityPluginBinding?.activity as FragmentActivity, serverUrl, jwt + ).activityClass(FlutterInstantPdfActivity::class.java) + .configuration(configurationAdapterInstant.build()).build() + activityPluginBinding?.activity?.startActivity(intentInstant) + callback(Result.success(activityPluginBinding?.activity != null)) + } catch (e: PSPDFKitException) { + callback(Result.failure(PspdfkitApiError("Error", e.message))) + } + } + + override fun setFormFieldValue( + value: String, fullyQualifiedName: String, callback: (Result) -> Unit + ) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val document = Preconditions.requireDocumentNotNull( + activityPluginBinding?.activity as PdfActivity, "Pspdfkit.setFormFieldValue(String)" + ) + disposable = document.formProvider.getFormElementWithNameAsync(fullyQualifiedName) + .subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()) + .subscribe({ formElement: FormElement? -> + if (formElement is TextFormElement) { + formElement.setText(value) + callback(Result.success(true)) + } else if (formElement is EditableButtonFormElement) { + when (value) { + "selected" -> { + formElement.select() + callback(Result.success(true)) + } + + "deselected" -> { + formElement.deselect() + callback(Result.success(true)) + } + + else -> { + callback(Result.success(false)) + } + } + } else if (formElement is ChoiceFormElement) { + val selectedIndexes: MutableList = ArrayList() + if (areValidIndexes(value, selectedIndexes)) { + formElement.selectedIndexes = selectedIndexes + callback(Result.success(true)) + } else { + callback( + Result.failure( + PspdfkitApiError( + "InvalidArgument", + "\"value\" argument needs a list of " + "integers to set selected indexes for a choice " + "form element (e.g.: \"1, 3, 5\")." + ) + ) + ) + } + } else if (formElement is SignatureFormElement) { + callback( + Result.failure( + PspdfkitApiError( + "UnsupportedOperation", + "Signature form elements are not supported." + ) + ) + ) + } else { + callback(Result.success(false)) + } + }, { throwable: Throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error", String.format( + "Error while searching for a form element with name %s", + fullyQualifiedName + ), throwable.message + ) + ) + ) + }, // Form element for the given name not found. + { callback(Result.success(false)) }) + + } + + override fun getFormFieldValue( + fullyQualifiedName: String, callback: (Result) -> Unit + ) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val document = Preconditions.requireDocumentNotNull( + activityPluginBinding?.activity as PdfActivity, "Pspdfkit.getFormFieldValue()" + ) + disposable = document.formProvider.getFormElementWithNameAsync(fullyQualifiedName) + .subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()) + .subscribe({ formElement: FormElement? -> + when (formElement) { + is TextFormElement -> { + val text = formElement.text + callback(Result.success(text)) + } + + is EditableButtonFormElement -> { + val isSelected = formElement.isSelected + callback(Result.success(if (isSelected) "selected" else "deselected")) + } + + is ChoiceFormElement -> { + val selectedIndexes = formElement.selectedIndexes + val stringBuilder = StringBuilder() + val iterator: Iterator = selectedIndexes.iterator() + while (iterator.hasNext()) { + stringBuilder.append(iterator.next()) + if (iterator.hasNext()) { + stringBuilder.append(",") + } + } + callback(Result.success(stringBuilder.toString())) + } + + is SignatureFormElement -> { + callback( + Result.failure( + PspdfkitApiError( + "UnsupportedOperation", + "Signature form elements are not supported." + ) + ) + ) + } + + else -> { + callback(Result.success(null)) + } + } + }, { throwable: Throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error", String.format( + "Error while searching for a form element with name %s", + fullyQualifiedName + ), throwable.message + ) + ) + ) + }, // Form element for the given name not found. + { + callback( + Result.failure( + PspdfkitApiError( + "Error", String.format( + "Form element not found with name %s", fullyQualifiedName + ) + ) + ) + ) + }) + } + + override fun applyInstantJson(annotationsJson: String, callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val document = Preconditions.requireDocumentNotNull( + activityPluginBinding?.activity as PdfActivity, "Pspdfkit.applyInstantJson(String)" + ) + val documentJsonDataProvider = DocumentJsonDataProvider(annotationsJson) + disposable = + DocumentJsonFormatter.importDocumentJsonAsync(document, documentJsonDataProvider) + .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) + .subscribe({ callback(Result.success(true)) }, { throwable: Throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error", + "Error while importing document Instant JSON", + throwable.message + ) + ) + ) + }) + } + + override fun exportInstantJson(callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val document = Preconditions.requireDocumentNotNull( + activityPluginBinding?.activity as PdfActivity, "Pspdfkit.exportInstantJson()" + ) + val outputStream = ByteArrayOutputStream() + + disposable = DocumentJsonFormatter.exportDocumentJsonAsync(document, outputStream) + .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe({ + callback(Result.success(outputStream.toString(StandardCharsets.UTF_8.name()))) + }, { throwable: Throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error", + "Error while exporting document Instant JSON", + throwable.message + ) + ) + ) + }) + } + + override fun addAnnotation(jsonAnnotation: String, callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val document = Preconditions.requireDocumentNotNull( + activityPluginBinding?.activity as PdfActivity, "Pspdfkit.exportInstantJson()" + ) + + disposable = + document.annotationProvider.createAnnotationFromInstantJsonAsync(jsonAnnotation) + .subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()) + .subscribe({ result -> + document.annotationProvider.addAnnotationToPage(result) + callback(Result.success(true)) + }) { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while creating annotation", + throwable.message ?: "", + ) + ) + ) + } + } + + override fun removeAnnotation(jsonAnnotation: String, callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val document = Preconditions.requireDocumentNotNull( + activityPluginBinding?.activity as PdfActivity, "Pspdfkit.exportInstantJson()" + ) + //Annotation from JSON. + val annotation = document.annotationProvider.createAnnotationFromInstantJson(jsonAnnotation) + document.annotationProvider.removeAnnotationFromPage(annotation) + callback(Result.success(true)) + } + + override fun getAnnotations(pageIndex: Long, type: String, callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val document = Preconditions.requireDocumentNotNull( + activityPluginBinding?.activity as PdfActivity, "Pspdfkit.exportInstantJson()" + ) + + val annotationJsonList = ArrayList() + // noinspection checkResult + document.annotationProvider.getAllAnnotationsOfTypeAsync( + AnnotationTypeAdapter.fromString( + type + ), pageIndex.toInt(), 1 + ).subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()) + .subscribe({ annotation -> + annotationJsonList.add(annotation.toInstantJson()) + }, { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while retrieving annotation of type $type", + throwable.message ?: "", + ) + ) + ) + }, { + callback(Result.success(annotationJsonList)) + }) + } + + override fun getAllUnsavedAnnotations(callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val document = Preconditions.requireDocumentNotNull( + activityPluginBinding?.activity as PdfActivity, "Pspdfkit.getAllUnsavedAnnotations()" + ) + + val outputStream = ByteArrayOutputStream() + disposable = DocumentJsonFormatter.exportDocumentJsonAsync(document, outputStream) + .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe({ + val jsonString: String = outputStream.toString() + callback(Result.success(jsonString)) + }, { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while getting unsaved JSON annotations.", + throwable.message ?: "", + ) + ) + ) + }) + } + + override fun processAnnotations( + type: com.pspdfkit.flutter.pspdfkit.api.AnnotationType, + processingMode: AnnotationProcessingMode, + destinationPath: String, + callback: (Result) -> Unit + ) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val document = Preconditions.requireDocumentNotNull( + activityPluginBinding?.activity as PdfActivity, "Pspdfkit.processAnnotations()" + ) + val annotationType = annotationTypeFromString(type.name) + val annotationProcessingMode = processModeFromString(processingMode.name) + + val task = if (type == com.pspdfkit.flutter.pspdfkit.api.AnnotationType.NONE) { + PdfProcessorTask.fromDocument(document).changeAllAnnotations(annotationProcessingMode) + } else { + PdfProcessorTask.fromDocument(document) + .changeAnnotationsOfType(annotationType, annotationProcessingMode) + } + + disposable = PdfProcessor.processDocumentAsync(task, File(destinationPath)) + .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(object : DisposableSubscriber() { + override fun onComplete() { + callback(Result.success(true)) + } + + override fun onNext(t: ProcessorProgress?) { + // Notify the progress. + } + + override fun onError(t: Throwable) { + callback( + Result.failure( + PspdfkitApiError( + "Error", "Error while processing annotations", t.message + ) + ) + ) + } + }) + } + + override fun importXfdf(xfdfPath: String, callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val document = Preconditions.requireDocumentNotNull( + activityPluginBinding?.activity as PdfActivity, "Pspdfkit.processAnnotations()" + ) + + val dataProvider = DocumentJsonDataProvider(xfdfPath) + // The async parse method is recommended (so you can easily offload parsing from the UI thread). + disposable = XfdfFormatter.parseXfdfAsync(document, dataProvider) + .subscribeOn(Schedulers.io()) // Specify the thread on which to parse XFDF. + .subscribe { annotations -> + // Annotations parsed from XFDF aren't added to the document automatically. + // You need to add them manually. + for (annotation in annotations) { + document.annotationProvider.addAnnotationToPage(annotation) + } + } + + } + + override fun exportXfdf(xfdfPath: String, callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val document = Preconditions.requireDocumentNotNull( + activityPluginBinding?.activity as PdfActivity, "Pspdfkit.processAnnotations()" + ) + // Output stream pointing to the XFDF file into which to write the data. + val outputStream = FileOutputStream(xfdfPath) + + // The async `write` method is recommended (so you can easily offload writing from the UI thread). + disposable = XfdfFormatter.writeXfdfAsync( + document, listOf(), listOf(), outputStream + ).subscribeOn(Schedulers.io()) // Specify the thread on which to write XFDF. + .subscribe({ + // XFDF was successfully written. + callback(Result.success(true)) + }, { throwable -> + // An error occurred while writing XFDF. + callback( + Result.failure( + PspdfkitApiError( + "Error while exporting XFDF", + throwable.message ?: "", + ) + ) + ) + }) + } + + override fun save(callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val document = Preconditions.requireDocumentNotNull( + activityPluginBinding?.activity as PdfActivity, "Pspdfkit.save()" + ) + disposable = document.saveIfModifiedAsync().subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { result: Boolean -> callback(Result.success(result)) } + } + + override fun setDelayForSyncingLocalChanges( + delay: Double, callback: (Result) -> Unit + ) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + + val document = Preconditions.requireDocumentNotNull( + instantActivity, "Pspdfkit.setDelayForSyncingLocalChanges()" + ) + (document as InstantPdfDocument).delayForSyncingLocalChanges = delay.toLong() + callback(Result.success(true)) + } + + override fun setListenToServerChanges(listen: Boolean, callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + + val document = Preconditions.requireDocumentNotNull( + instantActivity, "Pspdfkit.setListenToServerChanges()" + ) + (document as InstantPdfDocument).setListenToServerChanges(listen) + callback(Result.success(true)) + } + + override fun syncAnnotations(callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + + val document = Preconditions.requireDocumentNotNull( + instantActivity, "Pspdfkit.syncAnnotations()" + ) + disposable = + (document as InstantPdfDocument).syncAnnotationsAsync().subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ _: InstantProgress -> callback(Result.success(true)) }, + { throwable: Throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error", "Error while syncing annotations", throwable.message + ) + ) + ) + }) + } + + override fun checkAndroidWriteExternalStoragePermission(callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + + val permission = Manifest.permission.WRITE_EXTERNAL_STORAGE + val status = + checkPermission(activityPluginBinding?.activity as FragmentActivity, permission) + callback(Result.success(status)) + } + + override fun requestAndroidWriteExternalStoragePermission(callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + + val permission = Manifest.permission.WRITE_EXTERNAL_STORAGE + requestPermission(activityPluginBinding?.activity as FragmentActivity, permission) + callback(Result.success(AndroidPermissionStatus.NOT_DETERMINED)) + } + + override fun openAndroidSettings(callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + + openSettings(activityPluginBinding?.activity as FragmentActivity) + callback(Result.success(Unit)) + } + + override fun setAnnotationPresetConfigurations( + configurations: Map, callback: (Result) -> Unit + ) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val annotationConfigurations = configurations as Map<*, *> + val parsedConfigurations: List = + convertAnnotationConfigurations(instantActivity, annotationConfigurations) + + val pdfFragment = instantActivity.pdfFragment + for (config in parsedConfigurations) { + if (config.annotationTool != null && config.variant != null) { + pdfFragment.annotationConfiguration.put( + config.annotationTool, config.variant, config.configuration + ) + } + if (config.annotationTool != null && config.type == null) { + pdfFragment.annotationConfiguration.put( + config.annotationTool, config.configuration + ) + } + if (config.type != null) { + pdfFragment.annotationConfiguration.put( + config.type, config.configuration + ) + } + } + callback(Result.success(true)) + } + + override fun getTemporaryDirectory(callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + callback(Result.success(getTemporaryDirectory(activityPluginBinding?.activity as FragmentActivity))) + } + + override fun getAuthorName(callback: (Result) -> Unit) { + checkNotNull(activityPluginBinding) { "ActivityPluginBinding is null" } + val authorName = + PSPDFKitPreferences.get(activityPluginBinding?.activity as FragmentActivity) + .getAnnotationCreator("") + callback(Result.success(authorName ?: "")) + } + + override fun generatePdf( + pages: List>, + outputPath: String, + callback: (Result) -> Unit + ) { + + val adaptor = PdfPageAdaptor(activityPluginBinding!!.activity) + val documentPages = adaptor.parsePages(pages) + val task = PdfProcessorTask.empty() + + documentPages.forEachIndexed { index, newPage -> + task.addNewPage(newPage, index) + } + + val outputFile = File(outputPath) + disposable = PdfProcessor + .processDocumentAsync(task, outputFile) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + //Log progress + //Log.d("PDF Generation", "generatePdf: Processing page ${it.pagesProcessed + 1} of ${it.totalPages}") + }, { throwable -> + // Handle the error. + callback(Result.failure(PspdfkitApiError("Error generating PDF", throwable.message))) + }, { // Handle the completion. + callback(Result.success(outputPath)) + }) + } + + override fun generatePdfFromHtmlString( + html: String, + outPutFile: String, + options: Map?, + callback: (Result) -> Unit + ) { + + val outputFile = File(outPutFile)// Output file for the converted PDF. + + val converter = if (options?.contains("baseUrl") == true) activityPluginBinding?.let { + HtmlToPdfConverter.fromHTMLString( + it.activity, + html, + options["baseUrl"] as String + ) + } else activityPluginBinding?.let { HtmlToPdfConverter.fromHTMLString(it.activity, html) } + + if (options?.contains("enableJavaScript") == true) + converter?.setJavaScriptEnabled(options["enableJavaScript"] as Boolean) + + if (options?.contains("documentTitle") == true) + converter?.title(options["documentTitle"] as String) + + disposable = converter + // Perform the conversion. + ?.convertToPdfAsync(outputFile) + ?.subscribeOn(Schedulers.io()) + // Publish results on the main thread so we can update the UI. + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe( + { + callback(Result.success(outputFile.absolutePath)) + }, + { + callback(Result.failure(PspdfkitApiError("HTML_TO_PDF_ERROR", it.message))) + }) + } + + override fun generatePdfFromHtmlUri( + htmlUri: String, + outPutFile: String, + options: Map?, + callback: (Result) -> Unit + ) { + val outputFile = File(outPutFile)// Output file for the converted PDF. + val convertor = activityPluginBinding?.let { + HtmlToPdfConverter.fromUri( + it.activity, + Uri.parse(htmlUri) + ) + } + + // Configure javascript enabled + if (options?.contains("enableJavaScript") == true) { + convertor?.setJavaScriptEnabled(options["enableJavaScript"] as Boolean) + } + + // Configure title for the created document. + if (options?.contains("documentTitle") == true) { + convertor?.title(options["documentTitle"] as String) + } + + convertor?.let { + disposable = it + // Perform the conversion. + .convertToPdfAsync(outputFile) + // Subscribe to the conversion result. + .subscribe({ + // Return the converted document. + callback(Result.success(outputFile.absolutePath)) + }, { throwable -> + // Handle the error. + callback(Result.failure(PspdfkitApiError("", throwable.message))) + }) + } + } + + private fun setLicenseKey(activity: FragmentActivity, licenseKey: String?) { + try { + initialize( + activity, InitializationOptions( + licenseKey, + listOf(), + CrossPlatformTechnology.Flutter, + ) + ) + } catch (e: PSPDFKitException) { + throw IllegalStateException("Error while setting license key", e) + } + } + + private fun getTemporaryDirectory( + activity: FragmentActivity + ): String { + return activity.cacheDir.path + } + + private fun requestPermission( + activity: FragmentActivity, permission: String? + ) { + var permissionResult = permission + permissionResult = getManifestPermission(permission) + if (permission == null) { + return + } + val perm = arrayOf(permission) + ActivityCompat.requestPermissions(activity, perm, 0) + } + + private fun checkPermission( + activity: FragmentActivity, permission: String? + ): Boolean { + var permissionResult = permission + permissionResult = getManifestPermission(permission) + if (permissionResult == null) { + return false + } + return (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission( + activity, + permissionResult + )) + } + + private fun getManifestPermission(permission: String?): String? { + val res: String? = if ("WRITE_EXTERNAL_STORAGE" == permission) { + Manifest.permission.WRITE_EXTERNAL_STORAGE + } else { + null + } + return res + } + + private fun openSettings(activity: FragmentActivity) { + val intent = Intent( + Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.parse("package:" + activity.packageName) + ) + intent.addCategory(Intent.CATEGORY_DEFAULT) + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + activity.startActivity(intent) + } + + private val instantActivity: FlutterInstantPdfActivity + get() { + val instantPdfActivity = FlutterInstantPdfActivity.currentActivity + ?: throw IllegalStateException("No instant activity found") + return instantPdfActivity + } +} \ No newline at end of file diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitHTMLConverter.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitHTMLConverter.kt index cac111bb..7f35fb81 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitHTMLConverter.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitHTMLConverter.kt @@ -18,6 +18,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.schedulers.Schedulers import java.io.File +@Deprecated("This class is deprecated and will be removed in the future. Please use the new `PspdfkitApiImpl` class instead.") object PspdfkitHTMLConverter { @JvmStatic diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitPdfGenerator.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitPdfGenerator.kt index 69c6a287..9bc59aab 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitPdfGenerator.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitPdfGenerator.kt @@ -1,3 +1,12 @@ +/* + * Copyright © 2018-2024 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. + */ + package com.pspdfkit.flutter.pspdfkit import android.util.Log @@ -10,6 +19,7 @@ import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.schedulers.Schedulers import java.io.File +@Deprecated("This class is deprecated and will be removed in the future. Please use the new `PspdfkitViewImpl` class instead.") class PspdfkitPdfGenerator(private val pageAdaptor: PdfPageAdaptor) { private var disposable: Disposable? = null diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitPlugin.java b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitPlugin.java index 833278df..ff77ef59 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitPlugin.java +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitPlugin.java @@ -34,14 +34,14 @@ import com.pspdfkit.PSPDFKit; import com.pspdfkit.annotations.AnnotationType; -import com.pspdfkit.annotations.configuration.AnnotationConfiguration; -import com.pspdfkit.document.DocumentSaveOptions; import com.pspdfkit.document.PdfDocument; -import com.pspdfkit.document.PdfVersion; import com.pspdfkit.document.formatters.DocumentJsonFormatter; import com.pspdfkit.document.processor.PdfProcessor; import com.pspdfkit.document.processor.PdfProcessorTask; import com.pspdfkit.exceptions.PSPDFKitException; +import com.pspdfkit.flutter.pspdfkit.annotations.FlutterAnnotationPresetConfiguration; +import com.pspdfkit.flutter.pspdfkit.api.PspdfkitApi; +import com.pspdfkit.flutter.pspdfkit.api.PspdfkitFlutterApiCallbacks; import com.pspdfkit.flutter.pspdfkit.pdfgeneration.PdfPageAdaptor; import com.pspdfkit.flutter.pspdfkit.util.DocumentJsonDataProvider; import com.pspdfkit.flutter.pspdfkit.util.MeasurementHelper; @@ -83,7 +83,6 @@ import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subscribers.DisposableSubscriber; - /** * PSPDFKit plugin to load PDF and image documents. */ @@ -96,6 +95,7 @@ public class PspdfkitPlugin @NonNull private static final EventDispatcher eventDispatcher = EventDispatcher.getInstance(); private static final String LOG_TAG = "PSPDFKitPlugin"; + private static final String MESSAGE_CHANNEL_SUFFIX = "pspdfkit"; /** * Hybrid technology where the application is supposed to be working on. @@ -123,6 +123,8 @@ public PspdfkitPlugin() { @Nullable private List> measurementValueConfigurations; + private final PspdfkitApiImpl pspdfkitApi = new PspdfkitApiImpl(null); + /** * This {@code FlutterPlugin} has been associated with a {@link FlutterEngine} instance. * @@ -146,6 +148,10 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { "com.pspdfkit.widget", new PSPDFKitViewFactory(binding.getBinaryMessenger()) ); + // Setup the PSPDFKit API. + PspdfkitApi.Companion.setUp(binding.getBinaryMessenger(),pspdfkitApi,MESSAGE_CHANNEL_SUFFIX); + PspdfkitFlutterApiCallbacks pspdfkitFlutterApiCallbacks = new PspdfkitFlutterApiCallbacks(binding.getBinaryMessenger(),MESSAGE_CHANNEL_SUFFIX); + eventDispatcher.setPspdfkitApiCallbacks(new PspdfkitApiCallbacks(pspdfkitFlutterApiCallbacks)); } /** @@ -164,6 +170,8 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { if (disposable != null) { disposable.dispose(); } + PspdfkitApi.Companion.setUp(binding.getBinaryMessenger(),null,MESSAGE_CHANNEL_SUFFIX); + pspdfkitApi.dispose(); } @SuppressLint("CheckResult") @@ -285,7 +293,6 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { break; case "applyInstantJson": String annotationsJson = call.argument("annotationsJson"); - requireNotNullNotEmpty(annotationsJson, "annotationsJson"); document = requireDocumentNotNull( @@ -642,14 +649,14 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { } break; } - case "setAnnotationPresetConfigurations": { + case "setAnnotationConfigurations": { try { Map annotationConfigurations = call.argument("annotationConfigurations"); if (annotationConfigurations == null) { result.error("InvalidArgument", "Annotation configurations must be a valid map", null); return; } - Map configurations = + List configurations = AnnotationConfigurationAdaptor .convertAnnotationConfigurations(getInstantActivity(), annotationConfigurations); @@ -658,8 +665,26 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { result.error("InvalidState", "PdfFragment is null", null); return; } - for (Map.Entry entry : configurations.entrySet()) { - pdfFragment.getAnnotationConfiguration().put(entry.getKey(), entry.getValue()); + for (FlutterAnnotationPresetConfiguration config : configurations) { + if (config.getAnnotationTool() != null && config.getVariant() != null) { + pdfFragment.getAnnotationConfiguration().put( + config.getAnnotationTool(), + config.getVariant(), + config.getConfiguration() + ); + } + if (config.getAnnotationTool() != null && config.getType() == null) { + pdfFragment.getAnnotationConfiguration().put( + config.getAnnotationTool(), + config.getConfiguration() + ); + } + if (config.getType() != null) { + pdfFragment.getAnnotationConfiguration().put( + config.getType(), + config.getConfiguration() + ); + } } result.success(true); } catch (Exception e) { @@ -877,6 +902,7 @@ public boolean onRequestPermissionsResult( public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { activityPluginBinding = binding; binding.addRequestPermissionsResultListener(this); + pspdfkitApi.setActivityPluginBinding(activityPluginBinding); } @Override @@ -890,6 +916,7 @@ public void onReattachedToActivityForConfigChanges( ) { activityPluginBinding = binding; binding.addRequestPermissionsResultListener(this); + pspdfkitApi.setActivityPluginBinding(activityPluginBinding); } @Override @@ -901,6 +928,7 @@ private void detachActivityPluginBinding() { if (activityPluginBinding != null) { activityPluginBinding.removeRequestPermissionsResultListener(this); activityPluginBinding = null; + pspdfkitApi.setActivityPluginBinding(null); } } diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitViewImpl.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitViewImpl.kt new file mode 100644 index 00000000..00c34df7 --- /dev/null +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitViewImpl.kt @@ -0,0 +1,620 @@ +/* + * Copyright © 2024 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. + */ +package com.pspdfkit.flutter.pspdfkit + +import android.graphics.RectF +import com.pspdfkit.document.formatters.DocumentJsonFormatter +import com.pspdfkit.document.formatters.XfdfFormatter +import com.pspdfkit.document.processor.PdfProcessor +import com.pspdfkit.document.processor.PdfProcessor.ProcessorProgress +import com.pspdfkit.document.processor.PdfProcessorTask +import com.pspdfkit.flutter.pspdfkit.AnnotationConfigurationAdaptor.Companion.convertAnnotationConfigurations +import com.pspdfkit.flutter.pspdfkit.annotations.FlutterAnnotationPresetConfiguration +import com.pspdfkit.flutter.pspdfkit.api.AnnotationProcessingMode +import com.pspdfkit.flutter.pspdfkit.api.AnnotationType +import com.pspdfkit.flutter.pspdfkit.api.PdfRect +import com.pspdfkit.flutter.pspdfkit.api.PspdfkitApiError +import com.pspdfkit.flutter.pspdfkit.api.PspdfkitWidgetControllerApi +import com.pspdfkit.flutter.pspdfkit.util.DocumentJsonDataProvider +import com.pspdfkit.flutter.pspdfkit.util.Preconditions.requireNotNullNotEmpty +import com.pspdfkit.flutter.pspdfkit.util.ProcessorHelper.annotationTypeFromString +import com.pspdfkit.flutter.pspdfkit.util.ProcessorHelper.processModeFromString +import com.pspdfkit.flutter.pspdfkit.util.areValidIndexes +import com.pspdfkit.forms.ChoiceFormElement +import com.pspdfkit.forms.EditableButtonFormElement +import com.pspdfkit.forms.SignatureFormElement +import com.pspdfkit.forms.TextFormElement +import com.pspdfkit.ui.PdfUiFragment +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.disposables.Disposable +import io.reactivex.rxjava3.schedulers.Schedulers +import io.reactivex.rxjava3.subscribers.DisposableSubscriber +import java.io.ByteArrayOutputStream +import java.io.File +import java.io.FileOutputStream +import java.nio.charset.StandardCharsets +import java.util.Locale + +class PspdfkitViewImpl : PspdfkitWidgetControllerApi { + private var pdfUiFragment: PdfUiFragment? = null + private var disposable: Disposable? = null + + /** + * Sets the PdfFragment to be used by the controller. + * + * @param pdfFragment The PdfFragment to be used by the controller. + */ + fun setPdfFragment(pdfFragment: PdfUiFragment?) { + this.pdfUiFragment = pdfFragment + } + + /** + * Disposes the controller and releases all resources. + */ + fun dispose() { + pdfUiFragment = null + disposable?.dispose() + } + + override fun setFormFieldValue( + value: String, + fullyQualifiedName: String, + callback: (Result) -> Unit + ) { + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + // noinspection checkResult + document.formProvider + .getFormElementWithNameAsync(fullyQualifiedName) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { formElement -> + if (formElement is TextFormElement) { + formElement.setText(value) + callback(Result.success(true)) + } else if (formElement is EditableButtonFormElement) { + when (value) { + "selected" -> { + formElement.select() + callback(Result.success(true)) + } + + "deselected" -> { + formElement.deselect() + callback(Result.success(true)) + } + + else -> { + callback( + Result.failure( + PspdfkitApiError( + "Invalid value for editable button form element", + "Value must be either \"selected\" or \"deselected\"" + ) + ) + ) + } + } + } else if (formElement is ChoiceFormElement) { + val selectedIndexes: List = java.util.ArrayList() + if (areValidIndexes(value, selectedIndexes.toMutableList())) { + formElement.selectedIndexes = selectedIndexes + callback(Result.success(true)) + } else { + callback( + Result.failure( + PspdfkitApiError( + "Invalid value for choice form element", + "\"value\" argument needs a list of " + + "integers to set selected indexes for a choice " + + "form element (e.g.: \"1, 3, 5\").", + ) + ) + ) + } + } else if (formElement is SignatureFormElement) { + callback( + Result.failure( + PspdfkitApiError( + "Signature form elements cannot be set programmatically", + "Signature form elements are not supported.", + ) + ) + ) + } else { + callback( + Result.failure( + PspdfkitApiError( + "Invalid form element type", + "Form element with name $fullyQualifiedName is not a text, " + + "editable button, choice, or signature form element." + ) + ) + ) + } + }, + { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while searching for a form element with name $fullyQualifiedName", + throwable.message ?: "", + ) + ) + ) + } + ) // Form element for the given name not found. + { callback(Result.failure(PspdfkitApiError("Form element not found", ""))) } + } + + override fun getFormFieldValue( + fullyQualifiedName: String, + callback: (Result) -> Unit + ) { + checkNotNull(pdfUiFragment) + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + disposable = document.formProvider + .getFormElementWithNameAsync(fullyQualifiedName) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { formElement -> + when (formElement) { + is TextFormElement -> { + val text: String = formElement.text ?: "" + callback(Result.success(text)) + } + + is EditableButtonFormElement -> { + val isSelected: Boolean = + formElement.isSelected + callback(Result.success(if (isSelected) "selected" else "deselected")) + } + + is ChoiceFormElement -> { + val selectedIndexes: List = + formElement.selectedIndexes + val stringBuilder = StringBuilder() + val iterator = selectedIndexes.iterator() + while (iterator.hasNext()) { + stringBuilder.append(iterator.next()) + if (iterator.hasNext()) { + stringBuilder.append(",") + } + } + callback(Result.success(stringBuilder.toString())) + } + + is SignatureFormElement -> { + callback( + Result.failure( + PspdfkitApiError( + "Signature form elements cannot be read programmatically", + "Signature form elements are not supported.", + ) + ) + ) + } + + else -> { + callback( + Result.failure( + PspdfkitApiError( + "Invalid form element type", + "Form element with name $fullyQualifiedName is not a text, " + + "editable button, choice, or signature form element." + ) + ) + ) + } + } + }, + { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while searching for a form element with name $fullyQualifiedName", + throwable.message ?: "", + ) + ) + ) + } + ) // Form element for the given name not found. + { + callback( + Result.failure( + PspdfkitApiError( + "Form field not found.", + "Form element with name $fullyQualifiedName not found" + ) + ) + ) + } + } + + override fun applyInstantJson(annotationsJson: String, callback: (Result) -> Unit) { + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + val documentJsonDataProvider = DocumentJsonDataProvider( + requireNotNullNotEmpty( + annotationsJson, + "annotationsJson" + ) + ) + // noinspection checkResult + DocumentJsonFormatter.importDocumentJsonAsync(document, documentJsonDataProvider) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + callback(Result.success(true)) + } + ) { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Failed to apply Instant JSON", + throwable.message ?: "", + ) + ) + ) + } + } + + override fun exportInstantJson(callback: (Result) -> Unit) { + checkNotNull(pdfUiFragment) { "PdfFragment is not set" } + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + val outputStream = ByteArrayOutputStream() + + // noinspection checkResult + DocumentJsonFormatter.exportDocumentJsonAsync(document, outputStream) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + callback(Result.success(outputStream.toString(StandardCharsets.UTF_8.name()))) + } + ) { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Failed to export Instant JSON", + throwable.message ?: "", + ) + ) + ) + } + } + + override fun addAnnotation( + jsonAnnotation: String, + callback: (Result) -> Unit + ) { + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + disposable = + document.annotationProvider.createAnnotationFromInstantJsonAsync(jsonAnnotation) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + callback(Result.success(true)) + } + ) { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while creating annotation", + throwable.message ?: "", + ) + ) + ) + } + } + + override fun removeAnnotation(jsonAnnotation: String, callback: (Result) -> Unit) { + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + //Annotation from JSON. + val annotation = document.annotationProvider.createAnnotationFromInstantJson(jsonAnnotation) + document.annotationProvider.removeAnnotationFromPage(annotation) + callback(Result.success(true)) + } + + override fun getAnnotations(pageIndex: Long, type: String, callback: (Result) -> Unit) { + checkNotNull(pdfUiFragment) { "PdfFragment is not set" } + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + + val annotationJsonList = ArrayList() + // noinspection checkResult + document.annotationProvider.getAllAnnotationsOfTypeAsync( + AnnotationTypeAdapter.fromString( + type + ), + pageIndex.toInt(), 1 + ) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { annotation -> + annotationJsonList.add(annotation.toInstantJson()) + }, + { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while retrieving annotation of type $type", + throwable.message ?: "", + ) + ) + ) + }, + { + callback(Result.success(annotationJsonList)) + } + ) + } + + override fun getAllUnsavedAnnotations(callback: (Result) -> Unit) { + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + val outputStream = ByteArrayOutputStream() + + disposable = DocumentJsonFormatter.exportDocumentJsonAsync(document, outputStream) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + val jsonString: String = outputStream.toString() + callback(Result.success(jsonString)) + }, { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while getting unsaved JSON annotations.", + throwable.message ?: "", + ) + ) + ) + }) + } + + override fun processAnnotations( + type: AnnotationType, + processingMode: AnnotationProcessingMode, + destinationPath: String, + callback: (Result) -> Unit + ) { + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + // Get the annotation type and processing mode. + val annotationType = annotationTypeFromString( + type.name.toLowerCase(Locale.getDefault()) + ) + val annotationProcessingMode = + processModeFromString(processingMode.name.toLowerCase(Locale.getDefault())) + val outputPath = File(destinationPath) + + if (outputPath.parentFile?.exists() != true && outputPath.parentFile?.mkdirs() != true) { + callback( + Result.failure( + PspdfkitApiError( + "Invalid output path", + "Output path is invalid: $outputPath" + ) + ) + ) + return + } + // Check if we need to process all annotations or only annotations of a specific type. + val task = if (annotationType == com.pspdfkit.annotations.AnnotationType.NONE) { + PdfProcessorTask.fromDocument(document).changeAllAnnotations(annotationProcessingMode) + } else { + PdfProcessorTask.fromDocument(document) + .changeAnnotationsOfType(annotationType, annotationProcessingMode) + } + disposable = PdfProcessor.processDocumentAsync(task, outputPath) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(object : DisposableSubscriber() { + override fun onComplete() { + callback(Result.success(true)) + } + + override fun onNext(t: ProcessorProgress?) { + // No-op + } + + override fun onError(t: Throwable) { + callback( + Result.failure( + PspdfkitApiError( + "Error while processing annotations", + t.message ?: "", + ) + ) + ) + } + }) + } + + override fun importXfdf(xfdfPath: String, callback: (Result) -> Unit) { + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + val dataProvider = DocumentJsonDataProvider(xfdfPath) + // The async parse method is recommended (so you can easily offload parsing from the UI thread). + disposable = XfdfFormatter.parseXfdfAsync(document, dataProvider) + .subscribeOn(Schedulers.io()) // Specify the thread on which to parse XFDF. + .subscribe { annotations -> + // Annotations parsed from XFDF aren't added to the document automatically. + // You need to add them manually. + for (annotation in annotations) { + document.annotationProvider.addAnnotationToPage(annotation) + } + } + } + + override fun exportXfdf(xfdfPath: String, callback: (Result) -> Unit) { + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + + // Output stream pointing to the XFDF file into which to write the data. + val outputStream = FileOutputStream(xfdfPath) + + // The async `write` method is recommended (so you can easily offload writing from the UI thread). + disposable = XfdfFormatter.writeXfdfAsync( + document, + listOf(), + listOf(), + outputStream + ) + .subscribeOn(Schedulers.io()) // Specify the thread on which to write XFDF. + .subscribe( + { + // XFDF was successfully written. + callback(Result.success(true)) + }, + { throwable -> + // An error occurred while writing XFDF. + callback( + Result.failure( + PspdfkitApiError( + "Error while exporting XFDF", + throwable.message ?: "", + ) + ) + ) + } + ) + } + + override fun save(callback: (Result) -> Unit) { + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + disposable = document.saveIfModifiedAsync() + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + callback(Result.success(true)) + } + ) { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while saving document", + throwable.message ?: "", + ) + ) + ) + } + } + + override fun setAnnotationConfigurations( + configurations: Map>, + callback: (Result) -> Unit + ) { + val parsedConfigurations: List = + convertAnnotationConfigurations(pdfUiFragment!!.requireContext(), configurations) + + val pdfFragment = pdfUiFragment?.pdfFragment + + for (config in parsedConfigurations) { + if (config.annotationTool != null && config.variant != null) { + pdfFragment?.annotationConfiguration?.put( + config.annotationTool, config.variant, config.configuration + ) + } + if (config.annotationTool != null && config.type == null) { + pdfFragment?.annotationConfiguration?.put( + config.annotationTool, config.configuration + ) + } + if (config.type != null) { + pdfFragment?.annotationConfiguration?.put( + config.type, config.configuration + ) + } + } + callback(Result.success(true)) + } + + override fun getVisibleRect(pageIndex: Long, callback: (Result) -> Unit) { + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + + if (pageIndex < 0 || pageIndex >= document.pageCount) { + callback( + Result.failure( + PspdfkitApiError( + "Invalid page index", + "Page index must be in the range [0, ${document.pageCount})" + ) + ) + ) + } else { + val visiblePdfRect = RectF() + pdfUiFragment?.pdfFragment?.getVisiblePdfRect(visiblePdfRect, pageIndex.toInt()) + val pdfRect = PdfRect( + visiblePdfRect.left.toDouble(), + visiblePdfRect.top.toDouble(), + visiblePdfRect.width().toDouble(), + visiblePdfRect.height().toDouble() + ) + callback(Result.success(pdfRect)) + } + } + + override fun zoomToRect( + pageIndex: Long, + rect: PdfRect, + animated: Boolean?, + duration: Double?, + callback: (Result) -> Unit + ) { + checkNotNull(pdfUiFragment) { "PdfFragment is not set" } + try { + val x = requireNotNull(rect.x) + val y = requireNotNull(rect.y) + val width = requireNotNull(rect.width) + val height = requireNotNull(rect.height) + val zooRect = + RectF(x.toFloat(), y.toFloat(), (x + width).toFloat(), (y + height).toFloat()) + pdfUiFragment?.pdfFragment?.zoomTo(zooRect, pageIndex.toInt(), duration?.toLong() ?: 0) + callback(Result.success(true)) + } catch (e: Exception) { + callback( + Result.failure( + PspdfkitApiError( + "Error while zooming to rect", + e.message ?: "" + ) + ) + ) + } + } + + override fun getZoomScale(pageIndex: Long, callback: (Result) -> Unit) { + val document = requireNotNull(pdfUiFragment?.pdfFragment?.document) + if (pageIndex < 0 || pageIndex >= document.pageCount) { + callback( + Result.failure( + PspdfkitApiError( + "Invalid page index", + "Page index must be in the range [0, ${document.pageCount})" + ) + ) + ) + } else { + val zoomScale = pdfUiFragment?.pdfFragment?.getZoomScale(pageIndex.toInt()) + if (zoomScale != null) { + callback(Result.success(zoomScale.toDouble())) + } else { + callback( + Result.failure( + PspdfkitApiError( + "Error while getting zoom scale", + "Zoom scale is null" + ) + ) + ) + } + } + } +} \ No newline at end of file diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/annotations/FlutterAnnotationPresetConfiguration.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/annotations/FlutterAnnotationPresetConfiguration.kt new file mode 100644 index 00000000..3735d0b4 --- /dev/null +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/annotations/FlutterAnnotationPresetConfiguration.kt @@ -0,0 +1,11 @@ +package com.pspdfkit.flutter.pspdfkit.annotations + +import com.pspdfkit.annotations.AnnotationType +import com.pspdfkit.annotations.configuration.AnnotationConfiguration +import com.pspdfkit.ui.special_mode.controller.AnnotationTool +import com.pspdfkit.ui.special_mode.controller.AnnotationToolVariant + +data class FlutterAnnotationPresetConfiguration(val type: AnnotationType?, + val annotationTool:AnnotationTool?, + val variant: AnnotationToolVariant?, + val configuration:AnnotationConfiguration ) diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/api/PspdfkitApi.g.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/api/PspdfkitApi.g.kt new file mode 100644 index 00000000..fd7eb406 --- /dev/null +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/api/PspdfkitApi.g.kt @@ -0,0 +1,2239 @@ +// Copyright © 2024 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. +// Autogenerated from Pigeon (v22.5.0), do not edit directly. +// See also: https://pub.dev/packages/pigeon +@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") + +package com.pspdfkit.flutter.pspdfkit.api + +import android.util.Log +import io.flutter.plugin.common.BasicMessageChannel +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.MessageCodec +import io.flutter.plugin.common.StandardMessageCodec +import java.io.ByteArrayOutputStream +import java.nio.ByteBuffer + +private fun wrapResult(result: Any?): List { + return listOf(result) +} + +private fun wrapError(exception: Throwable): List { + return if (exception is PspdfkitApiError) { + listOf( + exception.code, + exception.message, + exception.details + ) + } else { + listOf( + exception.javaClass.simpleName, + exception.toString(), + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) + ) + } +} + +private fun createConnectionError(channelName: String): PspdfkitApiError { + return PspdfkitApiError("channel-error", "Unable to establish connection on channel: '$channelName'.", "")} + +/** + * Error class for passing custom error details to Flutter via a thrown PlatformException. + * @property code The error code. + * @property message The error message. + * @property details The error details. Must be a datatype supported by the api codec. + */ +class PspdfkitApiError ( + val code: String, + override val message: String? = null, + val details: Any? = null +) : Throwable() + +enum class AndroidPermissionStatus(val raw: Int) { + NOT_DETERMINED(0), + DENIED(1), + AUTHORIZED(2), + DENIED_NEVER_ASK(3); + + companion object { + fun ofRaw(raw: Int): AndroidPermissionStatus? { + return values().firstOrNull { it.raw == raw } + } + } +} + +/** Represents the native annotation type. */ +enum class AnnotationType(val raw: Int) { + ALL(0), + NONE(1), + UNDEFINED(2), + LINK(3), + HIGHLIGHT(4), + STRIKEOUT(5), + UNDERLINE(6), + SQUIGGLY(7), + FREE_TEXT(8), + INK(9), + SQUARE(10), + CIRCLE(11), + LINE(12), + NOTE(13), + STAMP(14), + CARET(15), + RICH_MEDIA(16), + SCREEN(17), + WIDGET(18), + FILE(19), + SOUND(20), + POLYGON(21), + POLYLINE(22), + POPUP(23), + WATERMARK(24), + TRAP_NET(25), + TYPE3D(26), + REDACT(27); + + companion object { + fun ofRaw(raw: Int): AnnotationType? { + return values().firstOrNull { it.raw == raw } + } + } +} + +enum class AnnotationTool(val raw: Int) { + INK_PEN(0), + INK_MAGIC(1), + INK_HIGHLIGHTER(2), + FREE_TEXT(3), + FREE_TEXT_CALL_OUT(4), + STAMP(5), + IMAGE(6), + HIGHLIGHT(7), + UNDERLINE(8), + SQUIGGLY(9), + STRIKE_OUT(10), + LINE(11), + ARROW(12), + SQUARE(13), + CIRCLE(14), + POLYGON(15), + POLYLINE(16), + ERASER(17), + CLOUDY(18), + LINK(19), + CARET(20), + RICH_MEDIA(21), + SCREEN(22), + FILE(23), + WIDGET(24), + REDACTION(25), + SIGNATURE(26), + STAMP_IMAGE(27), + NOTE(28), + SOUND(29), + MEASUREMENT_AREA_RECT(30), + MEASUREMENT_AREA_POLYGON(31), + MEASUREMENT_AREA_ELLIPSE(32), + MEASUREMENT_PERIMETER(33), + MEASUREMENT_DISTANCE(34); + + companion object { + fun ofRaw(raw: Int): AnnotationTool? { + return values().firstOrNull { it.raw == raw } + } + } +} + +enum class AnnotationToolVariant(val raw: Int) { + INK_PEN(0), + INK_MAGIC(1), + INK_HIGHLIGHTER(2), + FREE_TEXT(3), + FREE_TEXT_CALL_OUT(4), + STAMP(5), + IMAGE(6), + HIGHLIGHT(7), + UNDERLINE(8); + + companion object { + fun ofRaw(raw: Int): AnnotationToolVariant? { + return values().firstOrNull { it.raw == raw } + } + } +} + +enum class AnnotationProcessingMode(val raw: Int) { + FLATTEN(0), + REMOVE(1), + EMBED(2), + PRINT(3); + + companion object { + fun ofRaw(raw: Int): AnnotationProcessingMode? { + return values().firstOrNull { it.raw == raw } + } + } +} + +enum class DocumentPermissions(val raw: Int) { + /** Allow printing of document. */ + PRINTING(0), + /** Modify the contents of the document. */ + MODIFICATION(1), + /** Copy text and images from the document. */ + EXTRACT(2), + /** Add or modify text annotations, fill in interactive form fields. */ + ANNOTATIONS_AND_FORMS(3), + /** Fill in existing interactive form fields (including signature fields). */ + FILL_FORMS(4), + /** Extract text and images from the document. */ + EXTRACT_ACCESSIBILITY(5), + /** Assemble the document (insert, rotate, or delete pages and create document outline items or thumbnail images). */ + ASSEMBLE(6), + /** Print high quality. */ + PRINT_HIGH_QUALITY(7); + + companion object { + fun ofRaw(raw: Int): DocumentPermissions? { + return values().firstOrNull { it.raw == raw } + } + } +} + +/** The PDF version of a document. */ +enum class PdfVersion(val raw: Int) { + PDF_1_0(0), + PDF_1_1(1), + PDF_1_2(2), + PDF_1_3(3), + PDF_1_4(4), + PDF_1_5(5), + PDF_1_6(6), + PDF_1_7(7); + + companion object { + fun ofRaw(raw: Int): PdfVersion? { + return values().firstOrNull { it.raw == raw } + } + } +} + +enum class PdfFormFieldTypes(val raw: Int) { + TEXT(0), + CHECKBOX(1), + RADIO_BUTTON(2), + COMBO_BOX(3), + LIST_BOX(4), + SIGNATURE(5), + BUTTON(6), + UNKNOWN(7); + + companion object { + fun ofRaw(raw: Int): PdfFormFieldTypes? { + return values().firstOrNull { it.raw == raw } + } + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PdfRect ( + val x: Double, + val y: Double, + val width: Double, + val height: Double +) + { + companion object { + fun fromList(pigeonVar_list: List): PdfRect { + val x = pigeonVar_list[0] as Double + val y = pigeonVar_list[1] as Double + val width = pigeonVar_list[2] as Double + val height = pigeonVar_list[3] as Double + return PdfRect(x, y, width, height) + } + } + fun toList(): List { + return listOf( + x, + y, + width, + height, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PageInfo ( + /** The index of the page. This is a zero-based index. */ + val pageIndex: Long, + /** The height of the page in points. */ + val height: Double, + /** The width of the page in points. */ + val width: Double, + /** The rotation of the page in degrees. */ + val rotation: Long, + /** The label of the page. */ + val label: String +) + { + companion object { + fun fromList(pigeonVar_list: List): PageInfo { + val pageIndex = pigeonVar_list[0] as Long + val height = pigeonVar_list[1] as Double + val width = pigeonVar_list[2] as Double + val rotation = pigeonVar_list[3] as Long + val label = pigeonVar_list[4] as String + return PageInfo(pageIndex, height, width, rotation, label) + } + } + fun toList(): List { + return listOf( + pageIndex, + height, + width, + rotation, + label, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class DocumentSaveOptions ( + /** The password is used to encrypt the document. On Web, it's used as the user password. */ + val userPassword: String? = null, + /** The owner password is used to encrypt the document and set permissions. It's only used on Web. */ + val ownerPassword: String? = null, + /** Flatten annotations and form fields into the page content. */ + val flatten: Boolean? = null, + /** Whether to save the document incrementally. */ + val incremental: Boolean? = null, + /** The permissions to set on the document. See [DocumentPermissions] for more information. */ + val permissions: List? = null, + /** The PDF version to save the document as. */ + val pdfVersion: PdfVersion? = null, + /** Whether to exclude annotations from the exported document. */ + val excludeAnnotations: Boolean? = null, + /** Whether to exclude annotations that have the noPrint flag set to true from the exported document (Standalone only) */ + val saveForPrinting: Boolean? = null, + /** Whether to include comments in the exported document (Server-Backed only). */ + val includeComments: Boolean? = null, + /** Whether tp allow you to export a PDF in PDF/A format. */ + val outputFormat: Any? = null, + /** Whether to optimize the document for the web. */ + val optimize: Boolean? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): DocumentSaveOptions { + val userPassword = pigeonVar_list[0] as String? + val ownerPassword = pigeonVar_list[1] as String? + val flatten = pigeonVar_list[2] as Boolean? + val incremental = pigeonVar_list[3] as Boolean? + val permissions = pigeonVar_list[4] as List? + val pdfVersion = pigeonVar_list[5] as PdfVersion? + val excludeAnnotations = pigeonVar_list[6] as Boolean? + val saveForPrinting = pigeonVar_list[7] as Boolean? + val includeComments = pigeonVar_list[8] as Boolean? + val outputFormat = pigeonVar_list[9] + val optimize = pigeonVar_list[10] as Boolean? + return DocumentSaveOptions(userPassword, ownerPassword, flatten, incremental, permissions, pdfVersion, excludeAnnotations, saveForPrinting, includeComments, outputFormat, optimize) + } + } + fun toList(): List { + return listOf( + userPassword, + ownerPassword, + flatten, + incremental, + permissions, + pdfVersion, + excludeAnnotations, + saveForPrinting, + includeComments, + outputFormat, + optimize, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PdfFormOption ( + /** The value of the option. */ + val value: String, + /** The label of the option. */ + val label: String +) + { + companion object { + fun fromList(pigeonVar_list: List): PdfFormOption { + val value = pigeonVar_list[0] as String + val label = pigeonVar_list[1] as String + return PdfFormOption(value, label) + } + } + fun toList(): List { + return listOf( + value, + label, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FormFieldData ( + val name: String, + val alternativeFieldName: String? = null, + val fullyQualifiedName: String? = null, + val type: PdfFormFieldTypes, + val annotations: Any? = null, + val isReadOnly: Boolean? = null, + val isRequired: Boolean? = null, + val isExported: Boolean? = null, + val isDirty: Boolean? = null, + val options: List? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): FormFieldData { + val name = pigeonVar_list[0] as String + val alternativeFieldName = pigeonVar_list[1] as String? + val fullyQualifiedName = pigeonVar_list[2] as String? + val type = pigeonVar_list[3] as PdfFormFieldTypes + val annotations = pigeonVar_list[4] + val isReadOnly = pigeonVar_list[5] as Boolean? + val isRequired = pigeonVar_list[6] as Boolean? + val isExported = pigeonVar_list[7] as Boolean? + val isDirty = pigeonVar_list[8] as Boolean? + val options = pigeonVar_list[9] as List? + return FormFieldData(name, alternativeFieldName, fullyQualifiedName, type, annotations, isReadOnly, isRequired, isExported, isDirty, options) + } + } + fun toList(): List { + return listOf( + name, + alternativeFieldName, + fullyQualifiedName, + type, + annotations, + isReadOnly, + isRequired, + isExported, + isDirty, + options, + ) + } +} +private open class PspdfkitApiPigeonCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 129.toByte() -> { + return (readValue(buffer) as Long?)?.let { + AndroidPermissionStatus.ofRaw(it.toInt()) + } + } + 130.toByte() -> { + return (readValue(buffer) as Long?)?.let { + AnnotationType.ofRaw(it.toInt()) + } + } + 131.toByte() -> { + return (readValue(buffer) as Long?)?.let { + AnnotationTool.ofRaw(it.toInt()) + } + } + 132.toByte() -> { + return (readValue(buffer) as Long?)?.let { + AnnotationToolVariant.ofRaw(it.toInt()) + } + } + 133.toByte() -> { + return (readValue(buffer) as Long?)?.let { + AnnotationProcessingMode.ofRaw(it.toInt()) + } + } + 134.toByte() -> { + return (readValue(buffer) as Long?)?.let { + DocumentPermissions.ofRaw(it.toInt()) + } + } + 135.toByte() -> { + return (readValue(buffer) as Long?)?.let { + PdfVersion.ofRaw(it.toInt()) + } + } + 136.toByte() -> { + return (readValue(buffer) as Long?)?.let { + PdfFormFieldTypes.ofRaw(it.toInt()) + } + } + 137.toByte() -> { + return (readValue(buffer) as? List)?.let { + PdfRect.fromList(it) + } + } + 138.toByte() -> { + return (readValue(buffer) as? List)?.let { + PageInfo.fromList(it) + } + } + 139.toByte() -> { + return (readValue(buffer) as? List)?.let { + DocumentSaveOptions.fromList(it) + } + } + 140.toByte() -> { + return (readValue(buffer) as? List)?.let { + PdfFormOption.fromList(it) + } + } + 141.toByte() -> { + return (readValue(buffer) as? List)?.let { + FormFieldData.fromList(it) + } + } + else -> super.readValueOfType(type, buffer) + } + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + when (value) { + is AndroidPermissionStatus -> { + stream.write(129) + writeValue(stream, value.raw) + } + is AnnotationType -> { + stream.write(130) + writeValue(stream, value.raw) + } + is AnnotationTool -> { + stream.write(131) + writeValue(stream, value.raw) + } + is AnnotationToolVariant -> { + stream.write(132) + writeValue(stream, value.raw) + } + is AnnotationProcessingMode -> { + stream.write(133) + writeValue(stream, value.raw) + } + is DocumentPermissions -> { + stream.write(134) + writeValue(stream, value.raw) + } + is PdfVersion -> { + stream.write(135) + writeValue(stream, value.raw) + } + is PdfFormFieldTypes -> { + stream.write(136) + writeValue(stream, value.raw) + } + is PdfRect -> { + stream.write(137) + writeValue(stream, value.toList()) + } + is PageInfo -> { + stream.write(138) + writeValue(stream, value.toList()) + } + is DocumentSaveOptions -> { + stream.write(139) + writeValue(stream, value.toList()) + } + is PdfFormOption -> { + stream.write(140) + writeValue(stream, value.toList()) + } + is FormFieldData -> { + stream.write(141) + writeValue(stream, value.toList()) + } + else -> super.writeValue(stream, value) + } + } +} + + +/** + * The API for interacting with a PDF document. + * + * Generated interface from Pigeon that represents a handler of messages from Flutter. + */ +interface PspdfkitApi { + fun getFrameworkVersion(callback: (Result) -> Unit) + fun setLicenseKey(licenseKey: String?, callback: (Result) -> Unit) + fun setLicenseKeys(androidLicenseKey: String?, iOSLicenseKey: String?, webLicenseKey: String?, callback: (Result) -> Unit) + fun present(document: String, configuration: Map?, callback: (Result) -> Unit) + fun presentInstant(serverUrl: String, jwt: String, configuration: Map?, callback: (Result) -> Unit) + fun setFormFieldValue(value: String, fullyQualifiedName: String, callback: (Result) -> Unit) + fun getFormFieldValue(fullyQualifiedName: String, callback: (Result) -> Unit) + fun applyInstantJson(annotationsJson: String, callback: (Result) -> Unit) + fun exportInstantJson(callback: (Result) -> Unit) + fun addAnnotation(jsonAnnotation: String, callback: (Result) -> Unit) + fun removeAnnotation(jsonAnnotation: String, callback: (Result) -> Unit) + fun getAnnotations(pageIndex: Long, type: String, callback: (Result) -> Unit) + fun getAllUnsavedAnnotations(callback: (Result) -> Unit) + fun processAnnotations(type: AnnotationType, processingMode: AnnotationProcessingMode, destinationPath: String, callback: (Result) -> Unit) + fun importXfdf(xfdfString: String, callback: (Result) -> Unit) + fun exportXfdf(xfdfPath: String, callback: (Result) -> Unit) + fun save(callback: (Result) -> Unit) + fun setDelayForSyncingLocalChanges(delay: Double, callback: (Result) -> Unit) + fun setListenToServerChanges(listen: Boolean, callback: (Result) -> Unit) + fun syncAnnotations(callback: (Result) -> Unit) + fun checkAndroidWriteExternalStoragePermission(callback: (Result) -> Unit) + fun requestAndroidWriteExternalStoragePermission(callback: (Result) -> Unit) + fun openAndroidSettings(callback: (Result) -> Unit) + fun setAnnotationPresetConfigurations(configurations: Map, callback: (Result) -> Unit) + fun getTemporaryDirectory(callback: (Result) -> Unit) + fun getAuthorName(callback: (Result) -> Unit) + /** + * Generate PDF from Images, Template, and Patterns. + * [pages]: [NewPage]s to be added to the PDF. + * [outputPath]: The path to the output file. + * Returns the path to the generated PDF path or null if the input is invalid or if the PDF generation fails. + */ + fun generatePdf(pages: List>, outputPath: String, callback: (Result) -> Unit) + /** + * Generates a PDF from HTML string. + * + * [html]: The HTML string to be converted to PDF. + * [outPutFile]: The path to the output file. + * Returns the path to the generated PDF file or null if the input is invalid or if the PDF generation fails. + */ + fun generatePdfFromHtmlString(html: String, outPutFile: String, options: Map?, callback: (Result) -> Unit) + fun generatePdfFromHtmlUri(htmlUri: String, outPutFile: String, options: Map?, callback: (Result) -> Unit) + + companion object { + /** The codec used by PspdfkitApi. */ + val codec: MessageCodec by lazy { + PspdfkitApiPigeonCodec() + } + /** Sets up an instance of `PspdfkitApi` to handle messages through the `binaryMessenger`. */ + @JvmOverloads + fun setUp(binaryMessenger: BinaryMessenger, api: PspdfkitApi?, messageChannelSuffix: String = "") { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getFrameworkVersion$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getFrameworkVersion{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setLicenseKey$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val licenseKeyArg = args[0] as String? + api.setLicenseKey(licenseKeyArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setLicenseKeys$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val androidLicenseKeyArg = args[0] as String? + val iOSLicenseKeyArg = args[1] as String? + val webLicenseKeyArg = args[2] as String? + api.setLicenseKeys(androidLicenseKeyArg, iOSLicenseKeyArg, webLicenseKeyArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.present$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val documentArg = args[0] as String + val configurationArg = args[1] as Map? + api.present(documentArg, configurationArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.presentInstant$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val serverUrlArg = args[0] as String + val jwtArg = args[1] as String + val configurationArg = args[2] as Map? + api.presentInstant(serverUrlArg, jwtArg, configurationArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setFormFieldValue$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val valueArg = args[0] as String + val fullyQualifiedNameArg = args[1] as String + api.setFormFieldValue(valueArg, fullyQualifiedNameArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getFormFieldValue$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val fullyQualifiedNameArg = args[0] as String + api.getFormFieldValue(fullyQualifiedNameArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.applyInstantJson$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val annotationsJsonArg = args[0] as String + api.applyInstantJson(annotationsJsonArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.exportInstantJson$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.exportInstantJson{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.addAnnotation$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val jsonAnnotationArg = args[0] as String + api.addAnnotation(jsonAnnotationArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.removeAnnotation$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val jsonAnnotationArg = args[0] as String + api.removeAnnotation(jsonAnnotationArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getAnnotations$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pageIndexArg = args[0] as Long + val typeArg = args[1] as String + api.getAnnotations(pageIndexArg, typeArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getAllUnsavedAnnotations$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getAllUnsavedAnnotations{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.processAnnotations$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val typeArg = args[0] as AnnotationType + val processingModeArg = args[1] as AnnotationProcessingMode + val destinationPathArg = args[2] as String + api.processAnnotations(typeArg, processingModeArg, destinationPathArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.importXfdf$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val xfdfStringArg = args[0] as String + api.importXfdf(xfdfStringArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.exportXfdf$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val xfdfPathArg = args[0] as String + api.exportXfdf(xfdfPathArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.save$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.save{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setDelayForSyncingLocalChanges$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val delayArg = args[0] as Double + api.setDelayForSyncingLocalChanges(delayArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setListenToServerChanges$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val listenArg = args[0] as Boolean + api.setListenToServerChanges(listenArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.syncAnnotations$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.syncAnnotations{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.checkAndroidWriteExternalStoragePermission$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.checkAndroidWriteExternalStoragePermission{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.requestAndroidWriteExternalStoragePermission$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.requestAndroidWriteExternalStoragePermission{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.openAndroidSettings$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.openAndroidSettings{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setAnnotationPresetConfigurations$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val configurationsArg = args[0] as Map + api.setAnnotationPresetConfigurations(configurationsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getTemporaryDirectory$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getTemporaryDirectory{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getAuthorName$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getAuthorName{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.generatePdf$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pagesArg = args[0] as List> + val outputPathArg = args[1] as String + api.generatePdf(pagesArg, outputPathArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.generatePdfFromHtmlString$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val htmlArg = args[0] as String + val outPutFileArg = args[1] as String + val optionsArg = args[2] as Map? + api.generatePdfFromHtmlString(htmlArg, outPutFileArg, optionsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.generatePdfFromHtmlUri$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val htmlUriArg = args[0] as String + val outPutFileArg = args[1] as String + val optionsArg = args[2] as Map? + api.generatePdfFromHtmlUri(htmlUriArg, outPutFileArg, optionsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} +/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */ +class PspdfkitFlutterApiCallbacks(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") { + companion object { + /** The codec used by PspdfkitFlutterApiCallbacks. */ + val codec: MessageCodec by lazy { + PspdfkitApiPigeonCodec() + } + } + /** onPAuse callback for FlutterPdfActivity */ + fun onPdfActivityOnPause(callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onPdfActivityOnPause$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(null) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + fun onPdfFragmentAdded(callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onPdfFragmentAdded$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(null) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + fun onDocumentLoaded(documentIdArg: String, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onDocumentLoaded$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(documentIdArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + /** ViewControllerWillDismiss callback for PDFViewController */ + fun onPdfViewControllerWillDismiss(callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onPdfViewControllerWillDismiss$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(null) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + /** ViewControllerDidDismiss callback for PDFViewController */ + fun onPdfViewControllerDidDismiss(callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onPdfViewControllerDidDismiss$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(null) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + /** Called when instant synchronization starts. */ + fun onInstantSyncStarted(documentIdArg: String, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncStarted$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(documentIdArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + /** Called when instant synchronization ends. */ + fun onInstantSyncFinished(documentIdArg: String, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncFinished$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(documentIdArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + /** Called when instant synchronization fails. */ + fun onInstantSyncFailed(documentIdArg: String, errorArg: String, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncFailed$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(documentIdArg, errorArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + /** Called when instant authentication is done. */ + fun onInstantAuthenticationFinished(documentIdArg: String, validJWTArg: String, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantAuthenticationFinished$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(documentIdArg, validJWTArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + /** Called when instant authentication fails. */ + fun onInstantAuthenticationFailed(documentIdArg: String, errorArg: String, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantAuthenticationFailed$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(documentIdArg, errorArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + /** + * Only available on iOS. + * Called when instant document download is done. + */ + fun onInstantDownloadFinished(documentIdArg: String, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantDownloadFinished$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(documentIdArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + /** + * Only available on iOS. + * Called when instant document download fails. + */ + fun onInstantDownloadFailed(documentIdArg: String, errorArg: String, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantDownloadFailed$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(documentIdArg, errorArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } +} +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ +interface PspdfkitWidgetControllerApi { + /** + * Sets the value of a form field by specifying its fully qualified field name. + * This method is deprecated. Use [PdfDocument.setFormFieldValue] instead. + */ + fun setFormFieldValue(value: String, fullyQualifiedName: String, callback: (Result) -> Unit) + /** Gets the form field value by specifying its fully qualified name. */ + fun getFormFieldValue(fullyQualifiedName: String, callback: (Result) -> Unit) + /** Applies Instant document JSON to the presented document. */ + fun applyInstantJson(annotationsJson: String, callback: (Result) -> Unit) + /** Exports Instant document JSON from the presented document. */ + fun exportInstantJson(callback: (Result) -> Unit) + /** + * Adds the given annotation to the presented document. + * `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + */ + fun addAnnotation(jsonAnnotation: String, callback: (Result) -> Unit) + /** + * Removes the given annotation from the presented document. + * `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + */ + fun removeAnnotation(jsonAnnotation: String, callback: (Result) -> Unit) + /** Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. */ + fun getAnnotations(pageIndex: Long, type: String, callback: (Result) -> Unit) + /** Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. */ + fun getAllUnsavedAnnotations(callback: (Result) -> Unit) + /** + * Processes annotations of the given type with the provided processing + * mode and stores the PDF at the given destination path. + */ + fun processAnnotations(type: AnnotationType, processingMode: AnnotationProcessingMode, destinationPath: String, callback: (Result) -> Unit) + /** Imports annotations from the XFDF file at the given path. */ + fun importXfdf(xfdfString: String, callback: (Result) -> Unit) + /** Exports annotations to the XFDF file at the given path. */ + fun exportXfdf(xfdfPath: String, callback: (Result) -> Unit) + /** + * Saves the document back to its original location if it has been changed. + * If there were no changes to the document, the document file will not be modified. + */ + fun save(callback: (Result) -> Unit) + /** + * Sets the annotation preset configurations for the given annotation tools. + * @param configurations A map of annotation tools and their corresponding configurations. + * @param modifyAssociatedAnnotations Whether to modify the annotations associated with the old configuration. Only used for Android. + * @return True if the configurations were set successfully, false otherwise. + */ + fun setAnnotationConfigurations(configurations: Map>, callback: (Result) -> Unit) + /** + * Gets the visible rect of the given page. + * pageIndex The index of the page. This is a zero-based index. + * Returns a [Future] that completes with the visible rect of the given page. + */ + fun getVisibleRect(pageIndex: Long, callback: (Result) -> Unit) + /** + * Zooms to the given rect on the given page. + * pageIndex The index of the page. This is a zero-based index. + * rect The rect to zoom to. + * Returns a [Future] that completes when the zoom operation is done. + */ + fun zoomToRect(pageIndex: Long, rect: PdfRect, animated: Boolean?, duration: Double?, callback: (Result) -> Unit) + /** + * Gets the zoom scale of the given page. + * pageIndex The index of the page. This is a zero-based index. + * Returns a [Future] that completes with the zoom scale of the given page. + */ + fun getZoomScale(pageIndex: Long, callback: (Result) -> Unit) + + companion object { + /** The codec used by PspdfkitWidgetControllerApi. */ + val codec: MessageCodec by lazy { + PspdfkitApiPigeonCodec() + } + /** Sets up an instance of `PspdfkitWidgetControllerApi` to handle messages through the `binaryMessenger`. */ + @JvmOverloads + fun setUp(binaryMessenger: BinaryMessenger, api: PspdfkitWidgetControllerApi?, messageChannelSuffix: String = "") { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.setFormFieldValue$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val valueArg = args[0] as String + val fullyQualifiedNameArg = args[1] as String + api.setFormFieldValue(valueArg, fullyQualifiedNameArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getFormFieldValue$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val fullyQualifiedNameArg = args[0] as String + api.getFormFieldValue(fullyQualifiedNameArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.applyInstantJson$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val annotationsJsonArg = args[0] as String + api.applyInstantJson(annotationsJsonArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.exportInstantJson$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.exportInstantJson{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.addAnnotation$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val jsonAnnotationArg = args[0] as String + api.addAnnotation(jsonAnnotationArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.removeAnnotation$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val jsonAnnotationArg = args[0] as String + api.removeAnnotation(jsonAnnotationArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getAnnotations$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pageIndexArg = args[0] as Long + val typeArg = args[1] as String + api.getAnnotations(pageIndexArg, typeArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getAllUnsavedAnnotations$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getAllUnsavedAnnotations{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.processAnnotations$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val typeArg = args[0] as AnnotationType + val processingModeArg = args[1] as AnnotationProcessingMode + val destinationPathArg = args[2] as String + api.processAnnotations(typeArg, processingModeArg, destinationPathArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.importXfdf$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val xfdfStringArg = args[0] as String + api.importXfdf(xfdfStringArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.exportXfdf$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val xfdfPathArg = args[0] as String + api.exportXfdf(xfdfPathArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.save$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.save{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.setAnnotationConfigurations$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val configurationsArg = args[0] as Map> + api.setAnnotationConfigurations(configurationsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getVisibleRect$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pageIndexArg = args[0] as Long + api.getVisibleRect(pageIndexArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.zoomToRect$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pageIndexArg = args[0] as Long + val rectArg = args[1] as PdfRect + val animatedArg = args[2] as Boolean? + val durationArg = args[3] as Double? + api.zoomToRect(pageIndexArg, rectArg, animatedArg, durationArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getZoomScale$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pageIndexArg = args[0] as Long + api.getZoomScale(pageIndexArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ +interface PdfDocumentApi { + /** + * Returns the page info for the given page index. + * pageIndex The index of the page. This is a zero-based index. + */ + fun getPageInfo(pageIndex: Long, callback: (Result) -> Unit) + /** + * Exports the document as a PDF. + * options:[DocumentSaveOptions] The options to use when exporting the document. + * Returns a [Uint8List] containing the exported PDF data. + */ + fun exportPdf(options: DocumentSaveOptions?, callback: (Result) -> Unit) + fun getFormField(fieldName: String, callback: (Result>) -> Unit) + /** Returns a list of all form fields in the document. */ + fun getFormFields(callback: (Result>>) -> Unit) + /** Sets the value of a form field by specifying its fully qualified field name. */ + fun setFormFieldValue(value: String, fullyQualifiedName: String, callback: (Result) -> Unit) + /** Gets the form field value by specifying its fully qualified name. */ + fun getFormFieldValue(fullyQualifiedName: String, callback: (Result) -> Unit) + /** Applies Instant document JSON to the presented document. */ + fun applyInstantJson(annotationsJson: String, callback: (Result) -> Unit) + /** Exports Instant document JSON from the presented document. */ + fun exportInstantJson(callback: (Result) -> Unit) + /** + * Adds the given annotation to the presented document. + * `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + */ + fun addAnnotation(jsonAnnotation: String, callback: (Result) -> Unit) + /** + * Removes the given annotation from the presented document. + * `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + */ + fun removeAnnotation(jsonAnnotation: String, callback: (Result) -> Unit) + /** Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. */ + fun getAnnotations(pageIndex: Long, type: String, callback: (Result) -> Unit) + /** Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. */ + fun getAllUnsavedAnnotations(callback: (Result) -> Unit) + /** Imports annotations from the XFDF file at the given path. */ + fun importXfdf(xfdfString: String, callback: (Result) -> Unit) + /** Exports annotations to the XFDF file at the given path. */ + fun exportXfdf(xfdfPath: String, callback: (Result) -> Unit) + /** + * Saves the document back to its original location if it has been changed. + * If there were no changes to the document, the document file will not be modified. + */ + fun save(outputPath: String?, options: DocumentSaveOptions?, callback: (Result) -> Unit) + + companion object { + /** The codec used by PdfDocumentApi. */ + val codec: MessageCodec by lazy { + PspdfkitApiPigeonCodec() + } + /** Sets up an instance of `PdfDocumentApi` to handle messages through the `binaryMessenger`. */ + @JvmOverloads + fun setUp(binaryMessenger: BinaryMessenger, api: PdfDocumentApi?, messageChannelSuffix: String = "") { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getPageInfo$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pageIndexArg = args[0] as Long + api.getPageInfo(pageIndexArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.exportPdf$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val optionsArg = args[0] as DocumentSaveOptions? + api.exportPdf(optionsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getFormField$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val fieldNameArg = args[0] as String + api.getFormField(fieldNameArg) { result: Result> -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getFormFields$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getFormFields{ result: Result>> -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.setFormFieldValue$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val valueArg = args[0] as String + val fullyQualifiedNameArg = args[1] as String + api.setFormFieldValue(valueArg, fullyQualifiedNameArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getFormFieldValue$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val fullyQualifiedNameArg = args[0] as String + api.getFormFieldValue(fullyQualifiedNameArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.applyInstantJson$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val annotationsJsonArg = args[0] as String + api.applyInstantJson(annotationsJsonArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.exportInstantJson$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.exportInstantJson{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.addAnnotation$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val jsonAnnotationArg = args[0] as String + api.addAnnotation(jsonAnnotationArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.removeAnnotation$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val jsonAnnotationArg = args[0] as String + api.removeAnnotation(jsonAnnotationArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getAnnotations$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pageIndexArg = args[0] as Long + val typeArg = args[1] as String + api.getAnnotations(pageIndexArg, typeArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getAllUnsavedAnnotations$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getAllUnsavedAnnotations{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.importXfdf$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val xfdfStringArg = args[0] as String + api.importXfdf(xfdfStringArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.exportXfdf$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val xfdfPathArg = args[0] as String + api.exportXfdf(xfdfPathArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.save$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val outputPathArg = args[0] as String? + val optionsArg = args[1] as DocumentSaveOptions? + api.save(outputPathArg, optionsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} +/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */ +class PspdfkitWidgetCallbacks(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") { + companion object { + /** The codec used by PspdfkitWidgetCallbacks. */ + val codec: MessageCodec by lazy { + PspdfkitApiPigeonCodec() + } + } + fun onDocumentLoaded(documentIdArg: String, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onDocumentLoaded$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(documentIdArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + fun onDocumentError(documentIdArg: String, errorArg: String, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onDocumentError$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(documentIdArg, errorArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + fun onPageChanged(documentIdArg: String, pageIndexArg: Long, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onPageChanged$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(documentIdArg, pageIndexArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PspdfkitApiError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } +} diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/document/FlutterPdfDocument.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/document/FlutterPdfDocument.kt index d05b0090..62061a84 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/document/FlutterPdfDocument.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/document/FlutterPdfDocument.kt @@ -1,80 +1,561 @@ +/* + * Copyright © 2024 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. + */ + package com.pspdfkit.flutter.pspdfkit.document -import android.util.Log import com.pspdfkit.document.PdfDocument -import com.pspdfkit.flutter.pspdfkit.PSPDFKitView +import com.pspdfkit.document.formatters.DocumentJsonFormatter +import com.pspdfkit.document.formatters.XfdfFormatter +import com.pspdfkit.flutter.pspdfkit.AnnotationTypeAdapter +import com.pspdfkit.flutter.pspdfkit.api.DocumentSaveOptions +import com.pspdfkit.flutter.pspdfkit.api.PageInfo +import com.pspdfkit.flutter.pspdfkit.api.PdfDocumentApi +import com.pspdfkit.flutter.pspdfkit.api.PdfVersion +import com.pspdfkit.flutter.pspdfkit.api.PspdfkitApiError import com.pspdfkit.flutter.pspdfkit.forms.FormHelper -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import io.flutter.plugin.common.MethodChannel.MethodCallHandler +import com.pspdfkit.flutter.pspdfkit.util.DocumentJsonDataProvider +import com.pspdfkit.flutter.pspdfkit.util.Preconditions.requireNotNullNotEmpty +import com.pspdfkit.flutter.pspdfkit.util.areValidIndexes +import com.pspdfkit.forms.ChoiceFormElement +import com.pspdfkit.forms.EditableButtonFormElement +import com.pspdfkit.forms.SignatureFormElement +import com.pspdfkit.forms.TextFormElement +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.disposables.Disposable +import io.reactivex.rxjava3.schedulers.Schedulers +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.jsonObject +import java.io.ByteArrayOutputStream import java.io.File +import java.io.FileOutputStream +import java.nio.charset.StandardCharsets +import java.util.EnumSet class FlutterPdfDocument( - private val pdfDocument: PdfDocument, messenger: BinaryMessenger, -) : MethodCallHandler { - init { - val channel = MethodChannel(messenger, "com.pspdfkit.document.${pdfDocument.uid}") - channel.setMethodCallHandler(this) - } - - override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { - when (call.method) { - "getPageInfo" -> { - val pageIndex = call.argument("pageIndex") ?: -1 - if (pageIndex < 0 || pageIndex >= pdfDocument.pageCount) { - result.error("InvalidArgument", "pageIndex is required", null) - } else { - try { - val pageInfo = getPageInfo(pageIndex) - result.success(pageInfo) - } catch (e: Exception) { - result.error("Error", e.message, null) + private val pdfDocument: PdfDocument +) : PdfDocumentApi { + + private var disposable: Disposable? = null + private val documentPermissionsMap = mapOf( + "print" to com.pspdfkit.document.DocumentPermissions.PRINTING, + "modification" to com.pspdfkit.document.DocumentPermissions.MODIFICATION, + "fillForms" to com.pspdfkit.document.DocumentPermissions.FILL_FORMS, + "assemble" to com.pspdfkit.document.DocumentPermissions.ASSEMBLE, + "extractAccessibility" to com.pspdfkit.document.DocumentPermissions.EXTRACT_ACCESSIBILITY, + "extract" to com.pspdfkit.document.DocumentPermissions.EXTRACT, + "annotationsAndForms" to com.pspdfkit.document.DocumentPermissions.ANNOTATIONS_AND_FORMS, + "printHighQuality" to com.pspdfkit.document.DocumentPermissions.PRINT_HIGH_QUALITY, + ) + + private val pdfVersionMap = mapOf( + PdfVersion.PDF_1_0 to com.pspdfkit.document.PdfVersion.PDF_1_0, + PdfVersion.PDF_1_1 to com.pspdfkit.document.PdfVersion.PDF_1_1, + PdfVersion.PDF_1_2 to com.pspdfkit.document.PdfVersion.PDF_1_2, + PdfVersion.PDF_1_3 to com.pspdfkit.document.PdfVersion.PDF_1_3, + PdfVersion.PDF_1_4 to com.pspdfkit.document.PdfVersion.PDF_1_4, + PdfVersion.PDF_1_5 to com.pspdfkit.document.PdfVersion.PDF_1_5, + PdfVersion.PDF_1_6 to com.pspdfkit.document.PdfVersion.PDF_1_6, + PdfVersion.PDF_1_7 to com.pspdfkit.document.PdfVersion.PDF_1_7, + ) + + override fun getPageInfo(pageIndex: Long, callback: (Result) -> Unit) { + val width = pdfDocument.getPageSize(pageIndex.toInt()).width + val height = pdfDocument.getPageSize(pageIndex.toInt()).height + val label = pdfDocument.getPageLabel(pageIndex.toInt(), false) + val rotation = pdfDocument.getPageRotation(pageIndex.toInt()) + val pageInfo = + PageInfo(pageIndex, height.toDouble(), width.toDouble(), rotation.toLong(), label) + callback(Result.success(pageInfo)) + } + + override fun exportPdf(options: DocumentSaveOptions?, callback: (Result) -> Unit) { + val fileUrl = pdfDocument.documentSource.fileUri?.path + if (fileUrl == null) { + callback(Result.failure(Exception("Document source is not a file"))) + return + } + val data: ByteArray = fileUrl.let { File(it).readBytes() } + callback(Result.success(data)) + } + + override fun getFormField(fieldName: String, callback: (Result>) -> Unit) { + try { + val formField = pdfDocument.formProvider.getFormFieldWithFullyQualifiedName(fieldName) + if (formField == null) { + callback(Result.failure(Exception("Form field not found"))) + return + } + val formFieldData = FormHelper.formFieldPropertiesToMap(listOf(formField)) + callback(Result.success(formFieldData.first())) + } catch (e: Exception) { + callback(Result.failure(e)) + } + } + + override fun getFormFields(callback: (Result>>) -> Unit) { + try { + val formFields = pdfDocument.formProvider.formFields + val formFieldData = FormHelper.formFieldPropertiesToMap(formFields) + callback(Result.success(formFieldData)) + } catch (e: Exception) { + callback(Result.failure(e)) + } + } + + override fun setFormFieldValue( + value: String, + fullyQualifiedName: String, + callback: (Result) -> Unit + ) { + // noinspection checkResult + pdfDocument.formProvider + .getFormElementWithNameAsync(fullyQualifiedName) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { formElement -> + if (formElement is TextFormElement) { + formElement.setText(value) + callback(Result.success(true)) + } else if (formElement is EditableButtonFormElement) { + when (value) { + "selected" -> { + formElement.select() + callback(Result.success(true)) + } + + "deselected" -> { + formElement.deselect() + callback(Result.success(true)) + } + + else -> { + callback( + Result.failure( + PspdfkitApiError( + "Invalid value for editable button form element", + "Value must be either \"selected\" or \"deselected\"" + ) + ) + ) + } + } + } else if (formElement is ChoiceFormElement) { + val selectedIndexes: List = java.util.ArrayList() + if (areValidIndexes(value, selectedIndexes.toMutableList())) { + formElement.selectedIndexes = selectedIndexes + callback(Result.success(true)) + } else { + callback( + Result.failure( + PspdfkitApiError( + "Invalid value for choice form element", + "\"value\" argument needs a list of " + + "integers to set selected indexes for a choice " + + "form element (e.g.: \"1, 3, 5\").", + ) + ) + ) + } + } else if (formElement is SignatureFormElement) { + callback( + Result.failure( + PspdfkitApiError( + "Signature form elements cannot be set programmatically", + "Signature form elements are not supported.", + ) + ) + ) + } else { + callback( + Result.failure( + PspdfkitApiError( + "Invalid form element type", + "Form element with name $fullyQualifiedName is not a text, " + + "editable button, choice, or signature form element." + ) + ) + ) + } + }, + { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while searching for a form element with name $fullyQualifiedName", + throwable.message ?: "", + ) + ) + ) + } + ) // Form element for the given name not found. + { callback(Result.failure(PspdfkitApiError("Form element not found", ""))) } + } + + override fun getFormFieldValue( + fullyQualifiedName: String, + callback: (Result) -> Unit + ) { + disposable = pdfDocument.formProvider + .getFormElementWithNameAsync(fullyQualifiedName) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { formElement -> + when (formElement) { + is TextFormElement -> { + val text: String = formElement.text ?: "" + callback(Result.success(text)) + } + + is EditableButtonFormElement -> { + val isSelected: Boolean = + formElement.isSelected + callback(Result.success(if (isSelected) "selected" else "deselected")) + } + + is ChoiceFormElement -> { + val selectedIndexes: List = + formElement.selectedIndexes + val stringBuilder = StringBuilder() + val iterator = selectedIndexes.iterator() + while (iterator.hasNext()) { + stringBuilder.append(iterator.next()) + if (iterator.hasNext()) { + stringBuilder.append(",") + } + } + callback(Result.success(stringBuilder.toString())) + } + + is SignatureFormElement -> { + callback( + Result.failure( + PspdfkitApiError( + "Signature form elements cannot be read programmatically", + "Signature form elements are not supported.", + ) + ) + ) + } + + else -> { + callback( + Result.failure( + PspdfkitApiError( + "Invalid form element type", + "Form element with name $fullyQualifiedName is not a text, " + + "editable button, choice, or signature form element." + ) + ) + ) + } } + }, + { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while searching for a form element with name $fullyQualifiedName", + throwable.message ?: "", + ) + ) + ) } + ) // Form element for the given name not found. + { + callback( + Result.failure( + PspdfkitApiError( + "Form field not found.", + "Form element with name $fullyQualifiedName not found" + ) + ) + ) } - "getFormFields" -> { - try { - val formFields = pdfDocument.formProvider.formFields - val formFieldsMap = FormHelper.formFieldPropertiesToMap(formFields) - result.success(formFieldsMap) - } catch (e: Exception) { - result.error("Error", e.message, null) + } + + override fun applyInstantJson(annotationsJson: String, callback: (Result) -> Unit) { + val documentJsonDataProvider = DocumentJsonDataProvider( + requireNotNullNotEmpty( + annotationsJson, + "annotationsJson" + ) + ) + // noinspection checkResult + DocumentJsonFormatter.importDocumentJsonAsync(pdfDocument, documentJsonDataProvider) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + callback(Result.success(true)) } + ) { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Failed to apply Instant JSON", + throwable.message ?: "", + ) + ) + ) } - "exportPdf" -> { - try { - val fileUrl = pdfDocument.documentSource.fileUri?.path - if (fileUrl == null) { - result.error("DocumentException", "Document source is not a file", null) - return - } - val data:ByteArray = fileUrl.let { File(it).readBytes() } - result.success(data) - } catch (e: Exception) { - Log.e(LOG_TAG, "Error while exporting PDF", e) - result.error("DocumentException", e.message, null) + } + + override fun exportInstantJson(callback: (Result) -> Unit) { + val outputStream = ByteArrayOutputStream() + + // noinspection checkResult + DocumentJsonFormatter.exportDocumentJsonAsync(pdfDocument, outputStream) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + callback(Result.success(outputStream.toString(StandardCharsets.UTF_8.name()))) } + ) { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Failed to export Instant JSON", + throwable.message ?: "", + ) + ) + ) } + } - else -> { - result.notImplemented() + override fun addAnnotation( + jsonAnnotation: String, + callback: (Result) -> Unit + ) { + disposable = + pdfDocument.annotationProvider.createAnnotationFromInstantJsonAsync(jsonAnnotation) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + callback(Result.success(true)) + } + ) { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while creating annotation", + throwable.message ?: "", + ) + ) + ) + } + } + + override fun removeAnnotation(jsonAnnotation: String, callback: (Result) -> Unit) { + // Annotation from JSON. + try { + val annotationObject:Map = Json.parseToJsonElement(jsonAnnotation).jsonObject.toMap() + // Remove escaped backslashes from the JSON string. + val name = annotationObject["name"] as String + val pageIndex = annotationObject["pageIndex"] as Int + + val allAnnotations = pdfDocument.annotationProvider.getAnnotations(pageIndex) + val annotation = allAnnotations.firstOrNull { it.name == name } + if (annotation == null) { + callback(Result.failure(Exception("Annotation not found"))) + return } + pdfDocument.annotationProvider.removeAnnotationFromPage(annotation) + callback(Result.success(true)) + } catch (e: Exception) { + callback(Result.failure(e)) } } - private fun getPageInfo(pageIndex: Int): Map { - val pageInfo = mapOf( - "width" to pdfDocument.getPageSize(pageIndex).width, - "height" to pdfDocument.getPageSize(pageIndex).height, - "label" to pdfDocument.getPageLabel(pageIndex, false), - "index" to pageIndex, - "rotation" to pdfDocument.getPageRotation(pageIndex) + override fun getAnnotations(pageIndex: Long, type: String, callback: (Result) -> Unit) { + + val annotationJsonList = ArrayList() + // noinspection checkResult + pdfDocument.annotationProvider.getAllAnnotationsOfTypeAsync( + AnnotationTypeAdapter.fromString( + type + ), + pageIndex.toInt(), 1 + ) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { annotation -> + annotationJsonList.add(annotation.toInstantJson()) + }, + { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while retrieving annotation of type $type", + throwable.message ?: "", + ) + ) + ) + }, + { + callback(Result.success(annotationJsonList)) + } + ) + } + + override fun getAllUnsavedAnnotations(callback: (Result) -> Unit) { + val outputStream = ByteArrayOutputStream() + disposable = DocumentJsonFormatter.exportDocumentJsonAsync(pdfDocument, outputStream) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + val jsonString: String = outputStream.toString() + callback(Result.success(jsonString)) + }, { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while getting unsaved JSON annotations.", + throwable.message ?: "", + ) + ) + ) + }) + } + + override fun importXfdf(xfdfString: String, callback: (Result) -> Unit) { + val dataProvider = DocumentJsonDataProvider(xfdfString) + // The async parse method is recommended (so you can easily offload parsing from the UI thread). + disposable = XfdfFormatter.parseXfdfAsync(pdfDocument, dataProvider) + .subscribeOn(Schedulers.io()) // Specify the thread on which to parse XFDF. + .subscribe { annotations -> + // Annotations parsed from XFDF aren't added to the document automatically. + // You need to add them manually. + for (annotation in annotations) { + pdfDocument.annotationProvider.addAnnotationToPage(annotation) + } + } + } + + override fun exportXfdf(xfdfPath: String, callback: (Result) -> Unit) { + // Output stream pointing to the XFDF file into which to write the data. + val outputStream = FileOutputStream(xfdfPath) + + // The async `write` method is recommended (so you can easily offload writing from the UI thread). + disposable = XfdfFormatter.writeXfdfAsync( + pdfDocument, + listOf(), + listOf(), + outputStream ) - return pageInfo + .subscribeOn(Schedulers.io()) // Specify the thread on which to write XFDF. + .subscribe( + { + // XFDF was successfully written. + callback(Result.success(true)) + }, + { throwable -> + // An error occurred while writing XFDF. + callback( + Result.failure( + PspdfkitApiError( + "Error while exporting XFDF", + throwable.message ?: "", + ) + ) + ) + } + ) } - companion object { - const val LOG_TAG = "FlutterPdfDocument" + override fun save( + outputPath: String?, + options: DocumentSaveOptions?, + callback: (Result) -> Unit + ) { + + if (outputPath != null && options != null) { + // noinspection checkResult + pdfDocument.saveIfModifiedAsync( + outputPath, + convertDocumentSaveOptions(options) + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + callback(Result.success(true)) + } + ) { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while saving document", + throwable.message ?: "", + ) + ) + ) + } + } else if (outputPath != null) { + disposable = pdfDocument.saveAsync(outputPath) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + callback(Result.success(true)) + } + ) { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while saving document", + throwable.message ?: "", + ) + ) + ) + } + + } else { + // noinspection checkResult + pdfDocument.saveIfModifiedAsync() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + callback(Result.success(true)) + } + ) { throwable -> + callback( + Result.failure( + PspdfkitApiError( + "Error while saving document", + throwable.message ?: "", + ) + ) + ) + } + } + } + + fun dispose() { + disposable?.dispose() + } + + private fun convertDocumentSaveOptions(options: DocumentSaveOptions): com.pspdfkit.document.DocumentSaveOptions { + + return com.pspdfkit.document.DocumentSaveOptions( + options.userPassword, + options.permissions?.map { documentPermissionsMap[it?.name] }?.let { + EnumSet.copyOf(it) + }, + options.incremental ?: false, + pdfVersionMap[options.pdfVersion] + ) } -} \ No newline at end of file +} + diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/forms/FormHelper.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/forms/FormHelper.kt index 666999b1..be1590df 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/forms/FormHelper.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/forms/FormHelper.kt @@ -1,5 +1,7 @@ package com.pspdfkit.flutter.pspdfkit.forms +import com.pspdfkit.flutter.pspdfkit.api.FormFieldData +import com.pspdfkit.flutter.pspdfkit.api.PdfFormFieldTypes import com.pspdfkit.forms.CheckBoxFormField import com.pspdfkit.forms.ComboBoxFormField import com.pspdfkit.forms.FormField @@ -12,12 +14,23 @@ import com.pspdfkit.internal.forms.getInputFormat object FormHelper { + private val formFieldTypeMap: Map = mapOf( + FormType.TEXT to PdfFormFieldTypes.TEXT, + FormType.CHECKBOX to PdfFormFieldTypes.CHECKBOX, + FormType.RADIOBUTTON to PdfFormFieldTypes.RADIO_BUTTON, + FormType.LISTBOX to PdfFormFieldTypes.LIST_BOX, + FormType.COMBOBOX to PdfFormFieldTypes.COMBO_BOX, + FormType.SIGNATURE to PdfFormFieldTypes.SIGNATURE, + FormType.PUSHBUTTON to PdfFormFieldTypes.BUTTON, + FormType.UNDEFINED to PdfFormFieldTypes.UNKNOWN + ) + @JvmStatic - fun formFieldPropertiesToMap(formFields: List): List> { - val formFieldsList: MutableList> = mutableListOf() + fun formFieldPropertiesToMap(formFields: List): List> { + val formFieldsList: MutableList> = mutableListOf() // Extract the common form fields properties. for (formField in formFields) { - val formFieldsMap: MutableMap = mutableMapOf() + val formFieldsMap: MutableMap = mutableMapOf() formFieldsMap["name"] = formField.name formFieldsMap["fullyQualifiedName"] = formField.fullyQualifiedName formFieldsMap["type"] = formField.type.name @@ -28,7 +41,7 @@ object FormHelper { formFieldsMap["alternateFieldName"] = formField.alternateFieldName formFieldsMap["mappingName"] = formField.mappingName formFieldsMap["annotation"] = formField.formElement.annotation.toInstantJson() - formFieldsMap["inputFormatString"] = formField.formElement.getFormatString() + formFieldsMap["inputFormatString"] = formField.formElement.getFormatString() ?: "" formFieldsMap["inputFormat"] = formField.formElement.getInputFormat().name // Extract the specific form field properties. @@ -38,16 +51,36 @@ object FormHelper { return formFieldsList } + fun formFieldsToFormFieldData(formFields: List):List { + val formFieldsList: MutableList = mutableListOf() + // Extract the common form fields properties. + for (formField in formFields) { + val formFieldData: FormFieldData = FormFieldData( + name = formField.name, + fullyQualifiedName = formField.fullyQualifiedName, + type = formFieldTypeMap[formField.type] ?: PdfFormFieldTypes.UNKNOWN, + isDirty = formField.isDirty, + isRequired = formField.isRequired, + isReadOnly = formField.isReadOnly, + isExported = formField.isExported, + alternativeFieldName = formField.alternateFieldName, + annotations = formField.formElement.annotation.toInstantJson(), + ) + formFieldsList.add(formFieldData) + } + return formFieldsList + } + @JvmStatic private fun getSpecificFormFieldProperties( formField: FormField, - map: MutableMap - ): Map { + map: MutableMap + ): Map { when (formField.type) { FormType.TEXT -> { val textFormField = formField as TextFormField - map["text"] = textFormField.formElement.text + map["text"] = textFormField.formElement.text ?: "" map["isMultiline"] = textFormField.formElement.isMultiLine map["isPassword"] = textFormField.formElement.isPassword map["isRichText"] = textFormField.formElement.isRichText @@ -55,6 +88,7 @@ object FormHelper { map["isFileSelect"] = textFormField.formElement.isFileSelect map["isSpellCheckEnabled"] = textFormField.formElement.isSpellCheckEnabled map["isScrollEnabled"] = textFormField.formElement.isScrollEnabled + map["annotations"] = textFormField.formElement.annotation.toInstantJson() } FormType.CHECKBOX -> { diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/pdfgeneration/PdfPageAdaptor.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/pdfgeneration/PdfPageAdaptor.kt index 87342a82..f6233ddf 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/pdfgeneration/PdfPageAdaptor.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/pdfgeneration/PdfPageAdaptor.kt @@ -13,13 +13,13 @@ import com.pspdfkit.utils.Size class PdfPageAdaptor(private val context: Context) { - fun parsePages(pages: List>): List { + fun parsePages(pages: List>): List { return pages.map { buildPage(it) } } - private fun buildPage(pageConfigurations: HashMap): NewPage { + private fun buildPage(pageConfigurations: Map): NewPage { val pageSize = resolvePageSize(pageConfigurations["pageSize"] as List); val page: NewPage.Builder = when (pageConfigurations["type"]) { "pattern" -> { @@ -57,7 +57,14 @@ class PdfPageAdaptor(private val context: Context) { } if (pageConfigurations.containsKey("rotation")) { - page.rotation(pageConfigurations["rotation"] as Int) + var pageRotation = pageConfigurations["rotation"] + + if (pageRotation is Long) { + pageRotation = pageRotation.toInt() + } else if (pageRotation !is Int) { + throw IllegalArgumentException("Invalid rotation") + } + page.rotation(pageRotation) } if (pageConfigurations.containsKey("margins")) { @@ -72,15 +79,23 @@ class PdfPageAdaptor(private val context: Context) { } private fun parsePdf(pageConfig: HashMap): PagePdf { + var pageIndex = pageConfig["pageIndex"] + + if (pageIndex is Long) { + pageIndex = pageIndex.toInt() + } else if (pageIndex !is Int) { + throw IllegalArgumentException("Invalid page index") + } + val pdfPage = if (pageConfig.containsKey("position")) PagePdf( context, Uri.parse(pageConfig["documentUri"] as String), - pageConfig["pageIndex"] as Int, + pageIndex, resolvePagePosition(pageConfig["position"] as String) ) else PagePdf( context, Uri.parse(pageConfig["documentUri"] as String), - pageConfig["pageIndex"] as Int, + pageIndex, ) return pdfPage.apply { if (pageConfig.containsKey("zOrder")) { @@ -90,15 +105,31 @@ class PdfPageAdaptor(private val context: Context) { } private fun parseImage(imageConfig: Map): PageImage { + return PageImage( context, Uri.parse(imageConfig["imageUri"] as String), resolvePagePosition(imageConfig["position"] as String), ).apply { if (imageConfig.containsKey("quality")) { - setJpegQuality(imageConfig["quality"] as Int) + var quality = imageConfig["quality"] + + if (quality is Long) { + quality = quality.toInt() + } else if (quality !is Int) { + throw IllegalArgumentException("Invalid quality") + } + + setJpegQuality(quality) } if (imageConfig.containsKey("rotation")) { - rotation = imageConfig["rotation"] as Int + var pageRotation = imageConfig["rotation"] + + if (pageRotation is Long) { + pageRotation = pageRotation.toInt() + } else if (pageRotation !is Int) { + throw IllegalArgumentException("Invalid rotation") + } + rotation = pageRotation } } } diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/toolbar/FlutterViewModeController.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/toolbar/FlutterViewModeController.kt index 49383e5d..88911bc7 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/toolbar/FlutterViewModeController.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/toolbar/FlutterViewModeController.kt @@ -12,13 +12,7 @@ */ package com.pspdfkit.flutter.pspdfkit.toolbar -import com.pspdfkit.flutter.pspdfkit.PSPDFKitView -import com.pspdfkit.ui.forms.FormEditingBar -import com.pspdfkit.ui.forms.FormEditingBar.OnFormEditingBarLifecycleListener -import com.pspdfkit.ui.special_mode.controller.TextSelectionController -import com.pspdfkit.ui.special_mode.manager.TextSelectionManager.OnTextSelectionModeChangeListener import com.pspdfkit.ui.toolbar.AnnotationCreationToolbar -import com.pspdfkit.ui.toolbar.AnnotationEditingToolbar import com.pspdfkit.ui.toolbar.ContextualToolbar import com.pspdfkit.ui.toolbar.ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener import com.pspdfkit.ui.toolbar.grouping.MenuItemGroupingRule diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 149b7250..07c17771 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -23,6 +23,10 @@ android { targetCompatibility JavaVersion.VERSION_17 } + kotlinOptions { + jvmTarget = "17" + } + defaultConfig { compileSdk androidCompileSdkVersion applicationId "com.pspdfkit.flutter.example" @@ -52,7 +56,7 @@ flutter { dependencies { implementation 'androidx.multidex:multidex:2.0.1' testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test:runner:1.5.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0' + androidTestImplementation 'androidx.test:runner:1.6.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7' } diff --git a/example/lib/examples.dart b/example/lib/examples.dart index db12735c..d647285c 100644 --- a/example/lib/examples.dart +++ b/example/lib/examples.dart @@ -144,14 +144,15 @@ List examples(BuildContext context) => [ 'Opens two different PDF documents simultaneously using two PSPDFKit Widgets.', onTap: () => pushTwoPspdfWidgetsSimultaneously(context), ), - PspdfkitExampleItem( - title: 'PSPDFKit Events Listeners', - description: 'Shows how to use PSPDFKit Events Listeners.', - onTap: () async { - await extractAsset(context, _documentPath).then((value) => goTo( - PspdfkitEventListenerExample(documentPath: value.path), - context)); - }), + if (kIsWeb) + PspdfkitExampleItem( + title: 'PSPDFKit Events Listeners', + description: 'Shows how to use PSPDFKit Events Listeners.', + onTap: () async { + await extractAsset(context, _documentPath).then((value) => goTo( + PspdfkitEventListenerExample(documentPath: value.path), + context)); + }), PspdfkitExampleItem( title: 'Measurement tools', description: 'Shows how to use PSPDFKit Measurement tools.', @@ -332,7 +333,7 @@ void annotationsExample(context) async { void pdfGenerationExample(context) async { await Navigator.of(context).push(MaterialPageRoute( - builder: (_) => PspdfkitPDFGenerationExampleWidget())); + builder: (_) => const PspdfkitPDFGenerationExampleWidget())); } void manualSaveExample(context) async { diff --git a/example/lib/instant_collaboration_web.dart b/example/lib/instant_collaboration_web.dart index 5d11cfae..157b11be 100644 --- a/example/lib/instant_collaboration_web.dart +++ b/example/lib/instant_collaboration_web.dart @@ -16,10 +16,6 @@ class InstantCollaborationWeb extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - extendBodyBehindAppBar: PlatformUtils.isAndroid(), - // Do not resize the the document view on Android or - // it won't be rendered correctly when filling forms. - resizeToAvoidBottomInset: PlatformUtils.isIOS(), appBar: AppBar( title: const Text('Instant Collaboration Web'), ), @@ -30,14 +26,75 @@ class InstantCollaborationWeb extends StatelessWidget { padding: PlatformUtils.isAndroid() ? const EdgeInsets.only(top: kToolbarHeight) : null, - child: PspdfkitWidget( - documentPath: '', - configuration: PdfConfiguration( - webConfiguration: PdfWebConfiguration( - serverUrl: 'http://localhost:8080/', - instant: true, - documentId: 'example-document-id', - authPayload: {'jwt': ''})), - )))); + child: FutureBuilder?>( + future: instantCredentials(context), + builder: (context, snapshot) { + if (snapshot.data == null) { + return const Center( + child: Text( + 'Please enter Instant Collaboration credentials.'), + ); + } + return PspdfkitWidget( + documentPath: '', + configuration: PdfConfiguration( + webConfiguration: PdfWebConfiguration( + serverUrl: snapshot.data?['serverUrl'], + instant: true, + documentId: snapshot.data?['documentId'], + authPayload: { + 'jwt': snapshot.data?['jwt'], + })), + ); + })))); + } + + Future?> instantCredentials(BuildContext context) async { + // Show dialog to capture the server URL, document ID, and JWT. + return showAdaptiveDialog>( + context: context, + builder: (context) { + final serverUrlController = TextEditingController(); + final documentIdController = TextEditingController(); + final jwtController = TextEditingController(); + return AlertDialog( + title: const Text('Enter Instant Collaboration Credentials'), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + controller: serverUrlController, + decoration: const InputDecoration(labelText: 'Server URL'), + ), + TextField( + controller: documentIdController, + decoration: const InputDecoration(labelText: 'Document ID'), + ), + TextField( + controller: jwtController, + decoration: const InputDecoration(labelText: 'JWT'), + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop({ + 'serverUrl': serverUrlController.text, + 'documentId': documentIdController.text, + 'jwt': jwtController.text, + }); + }, + child: const Text('OK'), + ), + ], + ); + }); } } diff --git a/example/lib/main.dart b/example/lib/main.dart index 3ed6be94..c2d08f30 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -24,15 +24,14 @@ void main() { WidgetsFlutterBinding.ensureInitialized(); // Since PSPDFKit for Flutter 3.9.0, you are now required to initialize PSPDFKit with a license key. // If you don't have one, you can set it to null. This will show a watermark on the document. - // To get a trial license key, please visit https://my.pspdfkit.com/trial/new + // To get a trial license key, please visit https://my.nutrient.io/trial/new // // To set the license key for both platforms, use: // Pspdfkit.setLicenseKeys("YOUR_FLUTTER_ANDROID_LICENSE_KEY_GOES_HERE", // "YOUR_FLUTTER_IOS_LICENSE_KEY_GOES_HERE", "YOUR_FLUTTER_WEB_LICENSE_KEY_GOES_HERE"); // // To set the license key for the currently running platform, use: - // Pspdfkit.setLicenseKey(null); - Pspdfkit.setLicenseKey(null); + Pspdfkit.initialize(); runApp(const MyApp()); } diff --git a/example/lib/pspdfkit_annotation_preset_customisation.dart b/example/lib/pspdfkit_annotation_preset_customisation.dart index 9541be64..a7be2144 100644 --- a/example/lib/pspdfkit_annotation_preset_customisation.dart +++ b/example/lib/pspdfkit_annotation_preset_customisation.dart @@ -1,37 +1,50 @@ import 'package:flutter/material.dart'; import 'package:pspdfkit_flutter/pspdfkit.dart'; -class PspdfkitAnnotationPresetCustomization extends StatelessWidget { +class PspdfkitAnnotationPresetCustomization extends StatefulWidget { final String documentPath; const PspdfkitAnnotationPresetCustomization( {Key? key, required this.documentPath}) : super(key: key); + @override + State createState() => + _PspdfkitAnnotationPresetCustomizationState(); +} + +class _PspdfkitAnnotationPresetCustomizationState + extends State { + PspdfkitWidgetController? _controller; @override Widget build(BuildContext context) { return Scaffold( body: PspdfkitWidget( - documentPath: documentPath, + documentPath: widget.documentPath, onPspdfkitWidgetCreated: (controller) { + setState(() { + _controller = controller; + }); + }, + onPdfDocumentLoaded: (document) { try { - controller.setAnnotationConfigurations( + _controller?.setAnnotationConfigurations( { AnnotationTool.inkPen: InkAnnotationConfiguration( - color: Colors.red, + color: Colors.purple, availableColors: [ Colors.red, Colors.green, Colors.blue, Colors.yellow, - Colors.black + Colors.purple ], - thickness: 10, + thickness: 30, fillColor: Colors.white, - maxThickness: 20, + maxThickness: 30, minThickness: 5, maxAlpha: 1, minAlpha: 0.1, - alpha: 0.5, + alpha: 1, ), AnnotationTool.freeText: FreeTextAnnotationConfiguration( color: Colors.red, @@ -40,14 +53,10 @@ class PspdfkitAnnotationPresetCustomization extends StatelessWidget { alpha: 0.5, ), AnnotationTool.arrow: LineAnnotationConfiguration( - color: Colors.red, - thickness: 10, - fillColor: Colors.white, - alpha: 0.5, - lineEndingStyle: { - 'start': LineEndingStyle.openArrow, - 'end': LineEndingStyle.closedArrow - }), + color: Colors.green, + thickness: 20, + fillColor: Colors.white, + ), AnnotationTool.highlight: MarkupAnnotationConfiguration( color: Colors.red, ), diff --git a/example/lib/pspdfkit_annotations_example.dart b/example/lib/pspdfkit_annotations_example.dart index 8e7f7731..ae38c6c0 100644 --- a/example/lib/pspdfkit_annotations_example.dart +++ b/example/lib/pspdfkit_annotations_example.dart @@ -6,6 +6,10 @@ /// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. /// This notice may not be removed from this file. /// +// ignore_for_file: use_build_context_synchronously + +import 'dart:convert'; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:pspdfkit_flutter/pspdfkit.dart'; @@ -107,13 +111,14 @@ class PspdfkitAnnotationsExampleWidget extends StatefulWidget { : super(key: key); @override - _PspdfkitAnnotationsExampleWidgetState createState() => + State createState() => _PspdfkitAnnotationsExampleWidgetState(); } class _PspdfkitAnnotationsExampleWidgetState extends State { late PspdfkitWidgetController view; + late PdfDocument? document; @override Widget build(BuildContext context) { @@ -131,28 +136,30 @@ class _PspdfkitAnnotationsExampleWidgetState child: Column(children: [ Expanded( child: PspdfkitWidget( - onPspdfkitWidgetCreated: (controller) { - view = controller; - }, configuration: widget.configuration, documentPath: widget.documentPath, + onPdfDocumentLoaded: (document) { + setState(() { + this.document = document; + }); + }, ), ), SizedBox( child: Column(children: [ ElevatedButton( onPressed: () async { - await view.addAnnotation(annotationJsonHashMap); + await document?.addAnnotation(annotationJsonString); // To test the `view#addAnnotation` method with an InstantJSON string // simply use `annotationJsonString` instead or `annotationJsonHashMap`. - // E.g: `await view.addAnnotation(annotationJsonString);` + // E.g: `await document?.addAnnotation(annotationJsonString);` }, child: const Text('Add Annotation')), ElevatedButton( onPressed: () async { const title = 'Annotation JSON'; - await view - .getAnnotations(0, 'all') + await document + ?.getAnnotations(0, 'all') .then((dynamic annotationsJson) { showDialog( context: context, @@ -173,8 +180,8 @@ class _PspdfkitAnnotationsExampleWidgetState ElevatedButton( onPressed: () async { const title = 'Unsaved Annotations'; - await view - .getAllUnsavedAnnotations() + await document + ?.getAllUnsavedAnnotations() .then((dynamic annotationsJson) { showDialog( context: context, @@ -193,16 +200,16 @@ class _PspdfkitAnnotationsExampleWidgetState }); }, child: const Text('Get All Unsaved Annotations')), - if (PlatformUtils.isIOS() || kIsWeb) - ElevatedButton( - onPressed: () async { - dynamic annotationsJson = - await view.getAnnotations(0, 'all'); - for (var annotation in annotationsJson) { - await view.removeAnnotation(annotation); - } - }, - child: const Text('Remove Annotation')), + ElevatedButton( + onPressed: () async { + dynamic annotationsJson = + await document?.getAnnotations(0, 'all'); + for (var annotation in annotationsJson) { + await document + ?.removeAnnotation(jsonEncode(annotation)); + } + }, + child: const Text('Remove Annotation')), ])) ])))); } else { diff --git a/example/lib/pspdfkit_document_example.dart b/example/lib/pspdfkit_document_example.dart index ffb16595..87e3e8ca 100644 --- a/example/lib/pspdfkit_document_example.dart +++ b/example/lib/pspdfkit_document_example.dart @@ -1,3 +1,5 @@ +// ignore_for_file: use_build_context_synchronously + import 'dart:typed_data'; import 'package:flutter/material.dart'; @@ -65,7 +67,7 @@ class _PspdfkitDocumentExampleState extends State { : null, child: PspdfkitWidget( documentPath: widget.documentPath, - onPdfDocumentLoaded: (PdfDocument document) async { + onPdfDocumentLoaded: (PdfDocument document) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text('Document loaded ${document.documentId}'))); setState(() { @@ -73,9 +75,13 @@ class _PspdfkitDocumentExampleState extends State { }); }, onPageChanged: (pageIndex) { - _document?.getPageInfo(pageIndex).then((value) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Page changed to $value'))); + _document?.getPageInfo(pageIndex).then((PageInfo value) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + 'Page changed to ${value.pageIndex}, Rotation: ${value.rotation}'))); + }).catchError((error) { + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text('Error: $error'))); }); }, ))), diff --git a/example/lib/pspdfkit_form_example.dart b/example/lib/pspdfkit_form_example.dart index 77d744c7..1dadb990 100644 --- a/example/lib/pspdfkit_form_example.dart +++ b/example/lib/pspdfkit_form_example.dart @@ -7,6 +7,8 @@ /// This notice may not be removed from this file. /// +// ignore_for_file: use_build_context_synchronously + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -27,12 +29,11 @@ class PspdfkitFormExampleWidget extends StatefulWidget { }) : super(key: key); @override - _PspdfkitFormExampleWidgetState createState() => + State createState() => _PspdfkitFormExampleWidgetState(); } class _PspdfkitFormExampleWidgetState extends State { - late PspdfkitWidgetController view; late PdfDocument? document; @override @@ -54,19 +55,15 @@ class _PspdfkitFormExampleWidgetState extends State { child: Column(children: [ Expanded( child: PspdfkitWidget( - documentPath: widget.documentPath, - configuration: widget.configuration, - onPdfDocumentLoaded: (document) { - setState(() { - this.document = document; - }); - }, - onPspdfkitWidgetCreated: (controller) { - setState(() { - view = controller; - }); - onWidgetCreated(); - })), + documentPath: widget.documentPath, + configuration: widget.configuration, + onPdfDocumentLoaded: (document) { + setState(() { + this.document = document; + }); + onWidgetCreated(); + }, + )), Padding( padding: const EdgeInsets.all(8.0), child: SingleChildScrollView( @@ -76,7 +73,7 @@ class _PspdfkitFormExampleWidgetState extends State { children: [ ElevatedButton( onPressed: () { - view.setFormFieldValue( + document?.setFormFieldValue( 'Updated Form Field Value', 'Name_Last'); }, @@ -84,8 +81,8 @@ class _PspdfkitFormExampleWidgetState extends State { const SizedBox(width: 8), ElevatedButton( onPressed: () async { - await view - .getFormFieldValue('Name_Last') + await document + ?.getFormFieldValue('Name_Last') .then((formFieldValue) async { await showDialog( context: context, @@ -137,8 +134,10 @@ class _PspdfkitFormExampleWidgetState extends State { ], )); }).catchError((error) { - print( - 'Failed to get form fields: $error'); + if (kDebugMode) { + print( + 'Failed to get form fields: $error'); + } ScaffoldMessenger.of(context) .showSnackBar( SnackBar( @@ -161,26 +160,32 @@ class _PspdfkitFormExampleWidgetState extends State { void onWidgetCreated() async { try { - await view.setFormFieldValue('Lastname', 'Name_Last'); - await view.setFormFieldValue('0123456789', 'Telephone_Home'); - await view.setFormFieldValue('City', 'City'); - await view.setFormFieldValue('selected', 'Sex.0'); - await view.setFormFieldValue('deselected', 'Sex.1'); - await view.setFormFieldValue('selected', 'HIGH SCHOOL DIPLOMA'); + await document?.setFormFieldValue('Lastname', 'Name_Last'); + await document?.setFormFieldValue('0123456789', 'Telephone_Home'); + await document?.setFormFieldValue('City', 'City'); + await document?.setFormFieldValue('selected', 'Sex.0'); + await document?.setFormFieldValue('deselected', 'Sex.1'); + await document?.setFormFieldValue('selected', 'HIGH SCHOOL DIPLOMA'); } on PlatformException catch (e) { - print("Failed to set form field values '${e.message}'."); + if (kDebugMode) { + print("Failed to set form field values '${e.message}'."); + } } String? lastName; try { - lastName = await view.getFormFieldValue('Name_Last'); + lastName = await document?.getFormFieldValue('Name_Last'); } on PlatformException catch (e) { - print("Failed to get form field value '${e.message}'."); + if (kDebugMode) { + print("Failed to get form field value '${e.message}'."); + } } if (lastName != null) { - print( - "Retrieved form field for fully qualified name 'Name_Last' is $lastName."); + if (kDebugMode) { + print( + "Retrieved form field for fully qualified name 'Name_Last' is $lastName."); + } } } } diff --git a/example/lib/pspdfkit_instantjson_example.dart b/example/lib/pspdfkit_instantjson_example.dart index 0b27d1a5..34799af1 100644 --- a/example/lib/pspdfkit_instantjson_example.dart +++ b/example/lib/pspdfkit_instantjson_example.dart @@ -7,6 +7,8 @@ /// This notice may not be removed from this file. /// +// ignore_for_file: use_build_context_synchronously + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:pspdfkit_flutter/pspdfkit.dart'; @@ -28,13 +30,14 @@ class PspdfkitInstantJsonExampleWidget extends StatefulWidget { }) : super(key: key); @override - _PspdfkitInstantJsonExampleWidgetState createState() => + State createState() => _PspdfkitInstantJsonExampleWidgetState(); } class _PspdfkitInstantJsonExampleWidgetState extends State { - late PspdfkitWidgetController view; + // late PspdfkitWidgetController view; + late PdfDocument document; @override Widget build(BuildContext context) { @@ -48,70 +51,80 @@ class _PspdfkitInstantJsonExampleWidgetState child: Column(children: [ Expanded( child: PspdfkitWidget( - documentPath: widget.documentPath, - configuration: widget.configuration, - onPspdfkitWidgetCreated: - (PspdfkitWidgetController controller) { - setState(() { - view = controller; - }); - })), + documentPath: widget.documentPath, + configuration: widget.configuration, + onPdfDocumentLoaded: (document) { + setState(() { + this.document = document; + }); + }, + )), SizedBox( height: 80, - child: Row(children: [ - MaterialButton( - onPressed: () async { - final annotationsJson = - await DefaultAssetBundle.of(context) - .loadString(widget.instantJsonPath); - await view.applyInstantJson(annotationsJson); - }, - child: const Text('Apply Instant JSON')), - MaterialButton( - onPressed: () async { - const title = 'Exported Instant JSON'; - await view - .exportInstantJson() - .then((exportedInstantJson) async { - await showDialog( - context: context, - builder: (BuildContext context) => - AlertDialog( - title: const Text(title), - content: Text(exportedInstantJson ?? - 'No Instant JSON found.'), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context, - rootNavigator: false) - .pop(); - }, - child: const Text('OK')) - ], - )); - }); - }, - child: const Text('Export Instant JSON')), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row(children: [ + MaterialButton( + onPressed: () async { + final annotationsJson = + await DefaultAssetBundle.of(context) + .loadString(widget.instantJsonPath); + try { + await document + .applyInstantJson(annotationsJson); + } catch (e) { + if (kDebugMode) { + print('Error applying Instant JSON: $e'); + } + } + }, + child: const Text('Apply Instant JSON')), + MaterialButton( + onPressed: () async { + const title = 'Exported Instant JSON'; + await document + .exportInstantJson() + .then((exportedInstantJson) async { + await showDialog( + context: context, + builder: (BuildContext context) => + AlertDialog( + title: const Text(title), + content: Text(exportedInstantJson ?? + 'No Instant JSON found.'), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context, + rootNavigator: false) + .pop(); + }, + child: const Text('OK')) + ], + )); + }); + }, + child: const Text('Export Instant JSON')), - // xfdf example: - MaterialButton( - onPressed: () async { - if (widget.xfaPath == null) { - return; - } - final xfdfString = - await DefaultAssetBundle.of(context) - .loadString(widget.xfaPath!); - await view.importXfdf(xfdfString); - }, - child: const Text('Apply XFDF')), - MaterialButton( - onPressed: () async { - await view.exportXfdf('xfdf_export.xfdf'); - }, - child: const Text('Export XFDF')), - ])) + // xfdf example: + MaterialButton( + onPressed: () async { + if (widget.xfaPath == null) { + return; + } + final xfdfString = + await DefaultAssetBundle.of(context) + .loadString(widget.xfaPath!); + await document.importXfdf(xfdfString); + }, + child: const Text('Apply XFDF')), + MaterialButton( + onPressed: () async { + await document.exportXfdf('xfdf_export.xfdf'); + }, + child: const Text('Export XFDF')), + ]), + )) ]))); } else { return Text('$defaultTargetPlatform is not yet supported by pspdfkit.'); diff --git a/example/lib/pspdfkit_manual_save_example.dart b/example/lib/pspdfkit_manual_save_example.dart index 8d3ce46e..e740135e 100644 --- a/example/lib/pspdfkit_manual_save_example.dart +++ b/example/lib/pspdfkit_manual_save_example.dart @@ -22,7 +22,7 @@ class PspdfkitManualSaveExampleWidget extends StatefulWidget { : super(key: key); @override - _PspdfkitManualSaveExampleWidgetState createState() => + State createState() => _PspdfkitManualSaveExampleWidgetState(); } diff --git a/example/lib/pspdfkit_measurement_tools.dart b/example/lib/pspdfkit_measurement_tools.dart index c0d6caac..3aa594bb 100644 --- a/example/lib/pspdfkit_measurement_tools.dart +++ b/example/lib/pspdfkit_measurement_tools.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:pspdfkit_flutter/pspdfkit.dart'; @@ -43,11 +44,13 @@ class _PspdfkitMeasurementsExampleState _measurementValueConfiguration ], pageLayoutMode: PspdfkitPageLayoutMode.single, - webConfiguration: PdfWebConfiguration(toolbarItems: [ - ...Pspdfkit.defaultWebToolbarItems, - PspdfkitWebToolbarItem( - type: PspdfkitWebToolbarItemType.measurements) - ])), + webConfiguration: kIsWeb + ? PdfWebConfiguration(toolbarItems: [ + ...Pspdfkit.defaultWebToolbarItems, + PspdfkitWebToolbarItem( + type: PspdfkitWebToolbarItemType.measurements) + ]) + : null), ), ), ], diff --git a/example/lib/pspdfkit_pdf_generation_example.dart b/example/lib/pspdfkit_pdf_generation_example.dart index 07e950a8..00833aab 100644 --- a/example/lib/pspdfkit_pdf_generation_example.dart +++ b/example/lib/pspdfkit_pdf_generation_example.dart @@ -7,6 +7,8 @@ /// This notice may not be removed from this file. /// +// ignore_for_file: use_build_context_synchronously + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:pspdfkit_example/utils/file_utils.dart'; @@ -16,9 +18,7 @@ import 'package:pspdfkit_flutter/pspdfkit.dart'; import 'dart:io'; class PspdfkitPDFGenerationExampleWidget extends StatelessWidget { - final PspdfkitProcessor pdfProcessor = PspdfkitProcessor.instance; - - PspdfkitPDFGenerationExampleWidget({Key? key}) : super(key: key); + const PspdfkitPDFGenerationExampleWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -67,6 +67,11 @@ class PspdfkitPDFGenerationExampleWidget extends StatelessWidget { _generateFromHtmlUri(context).then((value) { _dismissProgressDialogue(context); Pspdfkit.present(value); + }).catchError((error) { + _dismissProgressDialogue(context); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text('Error generating PDF from HTML: $error'), + )); }); }, ), @@ -90,7 +95,7 @@ class PspdfkitPDFGenerationExampleWidget extends StatelessWidget { pageSize: PageSize.a4) ]; - var filePath = await pdfProcessor.generatePdf( + var filePath = await Pspdfkit.generatePdf( pages, outputPath); // or generatePDFFromImage if (filePath != null) { @@ -100,7 +105,7 @@ class PspdfkitPDFGenerationExampleWidget extends StatelessWidget { } } - /// Generates a PDF from an existig PDF document page. + /// Generates a PDF from an existing PDF document page. Future _generateFromTemplate(BuildContext context) async { File sourceDocument = await extractAsset(context, 'PDFs/PSPDFKit.pdf'); @@ -115,7 +120,7 @@ class PspdfkitPDFGenerationExampleWidget extends StatelessWidget { )) ]; - var filePath = await pdfProcessor.generatePdf(pages, outputPath); + var filePath = await Pspdfkit.generatePdf(pages, outputPath); if (filePath != null) { return filePath; @@ -140,7 +145,7 @@ class PspdfkitPDFGenerationExampleWidget extends StatelessWidget { NewPage.fromPattern(PagePattern.fromDocument(patternDocument.uri, 0), pageSize: PageSize.a4), ]; - var filePath = await pdfProcessor.generatePdf(pages, outputPath); + var filePath = await Pspdfkit.generatePdf(pages, outputPath); if (filePath != null) { return filePath; @@ -155,7 +160,7 @@ class PspdfkitPDFGenerationExampleWidget extends StatelessWidget { final outputFilePath = await getOutputPath('PDFs/html_String.pdf'); var filePath = - await pdfProcessor.generatePdfFromHtmlString(html, outputFilePath); + await Pspdfkit.generatePdfFromHtmlString(html, outputFilePath); if (filePath != null) { return filePath; @@ -172,8 +177,8 @@ class PspdfkitPDFGenerationExampleWidget extends StatelessWidget { String outputPath = await getOutputPath('pspdfkit_generated_html.pdf'); - var filePath = await pdfProcessor.generatePdfFromHtmlUri( - Uri.parse(htmlUri), outputPath); + var filePath = + await Pspdfkit.generatePdfFromHtmlUri(Uri.parse(htmlUri), outputPath); if (filePath != null) { return filePath; diff --git a/example/lib/pspdfkit_save_as_example.dart b/example/lib/pspdfkit_save_as_example.dart index 82a6642a..5e8926f6 100644 --- a/example/lib/pspdfkit_save_as_example.dart +++ b/example/lib/pspdfkit_save_as_example.dart @@ -25,7 +25,7 @@ class PspdfkitSaveAsExampleWidget extends StatefulWidget { : super(key: key); @override - _PspdfkitSaveAsExampleWidgetState createState() => + State createState() => _PspdfkitSaveAsExampleWidgetState(); } diff --git a/example/lib/pspdfkit_toolbar_customization.dart b/example/lib/pspdfkit_toolbar_customization.dart index dfae205e..e81c75f6 100644 --- a/example/lib/pspdfkit_toolbar_customization.dart +++ b/example/lib/pspdfkit_toolbar_customization.dart @@ -7,6 +7,7 @@ /// This notice may not be removed from this file. /// +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:pspdfkit_flutter/pspdfkit.dart'; @@ -20,7 +21,8 @@ class PspdfkitToolbarCustomization extends StatelessWidget { @override Widget build(BuildContext context) { // Get the default web toolbar items. - var defaultWebToolbarItems = Pspdfkit.defaultWebToolbarItems; + var defaultWebToolbarItems = + kIsWeb ? Pspdfkit.defaultWebToolbarItems : null; return Scaffold( extendBodyBehindAppBar: PlatformUtils.isAndroid(), @@ -59,7 +61,7 @@ class PspdfkitToolbarCustomization extends StatelessWidget { ], webConfiguration: PdfWebConfiguration( toolbarItems: [ - ...defaultWebToolbarItems.reversed, + ...defaultWebToolbarItems?.reversed ?? [], // Add custom web toolbar item. PspdfkitWebToolbarItem( type: PspdfkitWebToolbarItemType.custom, diff --git a/example/lib/pspdfkit_zoom_example.dart b/example/lib/pspdfkit_zoom_example.dart index 9986dae0..bd9f8239 100644 --- a/example/lib/pspdfkit_zoom_example.dart +++ b/example/lib/pspdfkit_zoom_example.dart @@ -1,3 +1,5 @@ +// ignore_for_file: use_build_context_synchronously + import 'package:flutter/material.dart'; import 'utils/platform_utils.dart'; import 'package:pspdfkit_flutter/pspdfkit.dart'; diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 6301287f..b0738364 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: pspdfkit_example description: Demonstrates how to use the pspdfkit plugin. -version: 3.12.1 +version: 4.0.0 homepage: https://pspdfkit.com/ publish_to: 'none' # Remove this line if you wish to publish to pub.dev environment: diff --git a/ios/Classes/AnnotationPresetConfigurations.swift b/ios/Classes/AnnotationPresetConfigurations.swift index aa77e5d8..f133ba8a 100644 --- a/ios/Classes/AnnotationPresetConfigurations.swift +++ b/ios/Classes/AnnotationPresetConfigurations.swift @@ -67,7 +67,7 @@ let ANNOTATION_MEASUREMENT_DISTANCE = "measurementDistance" @objc(AnnotationsPresetConfigurations) public class AnnotationsPresetConfigurations: NSObject { - @objc public static func setConfigurations(annotationPreset: Dictionary>) { + @objc public static func setConfigurations(annotationPreset: [String:[String: Any]]) { for key in annotationPreset.keys { switch key { diff --git a/ios/Classes/FlutterPdfDocument.swift b/ios/Classes/FlutterPdfDocument.swift index b386d597..58200b40 100644 --- a/ios/Classes/FlutterPdfDocument.swift +++ b/ios/Classes/FlutterPdfDocument.swift @@ -10,69 +10,242 @@ import Foundation @objc(FlutterPdfDocument) -public class FlutterPdfDocument: NSObject { +public class FlutterPdfDocument: NSObject, PdfDocumentApi { // MARK: - Properties var document: Document? - var messenger: FlutterBinaryMessenger? - var chanel: FlutterMethodChannel? + var pdfViewController: PDFViewController? - @objc public init(document: Document, messenger: FlutterBinaryMessenger) { + @objc public init(viewController: PDFViewController) { super.init() - self.document = document - self.messenger = messenger - self.chanel = FlutterMethodChannel(name: "com.pspdfkit.document."+document.uid, binaryMessenger: messenger) - self.chanel?.setMethodCallHandler({ - (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in - self.handleMethodCall(call: call, result: result) - }) - + self.document = viewController.document + self.pdfViewController = viewController + } + + func getPageInfo(pageIndex: Int64, completion: @escaping (Result) -> Void) { + let info = self.document?.pageInfoForPage(at: PageIndex(pageIndex)) + if (info == nil){ + completion(.failure(PspdfkitApiError(code: "Error while getting page info.", message: "Page info is nil", details: ""))) + return + } + let pageInfo: PageInfo = PageInfo(pageIndex: pageIndex, height: info!.size.height, width: info!.size.width, rotation: Int64(info!.savedRotation.rawValue), label: document?.pageLabelForPage(at: PageIndex(pageIndex), substituteWithPlainLabel:false) ?? "") + completion(.success(pageInfo)) + } + + func exportPdf(options: DocumentSaveOptions?, completion: @escaping (Result) -> Void) { + do { + let filePath = self.document?.fileURL?.path + if ((filePath) == nil){ + completion(.failure(PspdfkitApiError(code: "Error while exporting document.", message: "Filed path is null", details: ""))) + } + + let data = try Data(contentsOf: URL(fileURLWithPath: filePath!)) + let flutterStandardTypedData = FlutterStandardTypedData(bytes: data) + + completion(.success(flutterStandardTypedData)) + } catch let error { + completion(.failure(PspdfkitApiError(code: "Error while exporting document.", message: error.localizedDescription, details: ""))) + } } + + func getFormFields(completion: @escaping (Result<[[String : Any?]], any Error>) -> Void) { + do { + guard let document else { + let errorMessage = "Error while getting form field value for fields" + completion(.failure(PspdfkitApiError(code: "", message: errorMessage, details: nil))) + return + } + let value = try PspdfkitFlutterHelper.getFormFields(for: document) + completion(.success(value)) + } catch let error { + let errorMessage = "Error while getting form field value for fields \(error.localizedDescription)" + completion(.failure(PspdfkitApiError(code: "", message: errorMessage, details: nil))) + } + } + + func getFormField(fieldName: String, completion: @escaping (Result<[String : Any?], any Error>) -> Void) { + do { + guard let document else { + let errorMessage = "Error while getting form field value for fields" + completion(.failure(PspdfkitApiError(code: "", message: errorMessage, details: nil))) + return + } + + let value = try PspdfkitFlutterHelper.getFormFields(for: document) + let formField = value.first(where: { $0["name"] as? String == fieldName }) + + if formField == nil { + let errorMessage = "Error while getting form field value for fields" + completion(.failure(PspdfkitApiError(code: "", message: errorMessage, details: nil))) + } - private func handleMethodCall(call: FlutterMethodCall, result: @escaping FlutterResult) { - switch call.method { - case "getFormFields": - let formFields = self.document?.formParser?.forms - if (formFields == nil){ - result(FlutterError(code: "PdfDocumentError", message: "No form fields found", details: nil)) + completion(.success(formField!)) + } catch let error { + let errorMessage = "Error while getting form field value for fields \(error.localizedDescription)" + completion(.failure(PspdfkitApiError(code: "", message: errorMessage, details: nil))) + } + } + + func setFormFieldValue(value: String, fullyQualifiedName: String, completion: @escaping (Result) -> Void) { + do { + if document == nil { + let error = PspdfkitApiError(code: "", message: "Error while setting form field value for field name: \(fullyQualifiedName)", details: nil) + completion(.failure(error)) + return + } + let success = try PspdfkitFlutterHelper.setFormFieldValue(value, forFieldWithFullyQualifiedName: fullyQualifiedName, for: document!) + completion(.success(success)) + } catch let error { + completion(.failure(error)) + } + } + + func getFormFieldValue(fullyQualifiedName: String, completion: @escaping (Result) -> Void) { + do { + guard let document else { + completion(.failure(PspdfkitApiError(code: "", message: "Error while getting form field value for field name: \(fullyQualifiedName)", details: nil))) + return + } + let vale = try PspdfkitFlutterHelper.getFormFieldValue(forFieldWithFullyQualifiedName: fullyQualifiedName, for: document) + completion(.success("\(vale)")) + } catch let error { + completion(.failure(error)) + } + } + + func applyInstantJson(annotationsJson: String, completion: @escaping (Result) -> Void) { + do { + if document == nil { + let error = PspdfkitApiError(code: "", message: "Error while applying instant json for annotations: \(annotationsJson)", details: nil) + completion(.failure(error)) + return + } + let success = try PspdfkitFlutterHelper.applyInstantJson(annotationsJson: annotationsJson, document: document!) + pdfViewController?.reloadData() + completion(.success(success)) + } catch let error { + completion(.failure(error)) + } + } + + func exportInstantJson(completion: @escaping (Result) -> Void) { + do { + if document == nil { + let error = PspdfkitApiError(code: "", message: "Error while exporting instant json", details: nil) + completion(.failure(error)) + return + } + let json = try PspdfkitFlutterHelper.exportInstantJson(document: document!) + completion(.success(json)) + } catch let error { + completion(.failure(error)) + } + } + + func addAnnotation(jsonAnnotation: String, completion: @escaping (Result) -> Void) { + do { + if document == nil { + let error = PspdfkitApiError(code: "", message: "Error while adding annotation: \(jsonAnnotation)", details: nil) + completion(.failure(error)) + return + } + let success = try PspdfkitFlutterHelper.addAnnotation(jsonAnnotation, for: document!) + completion(.success(success)) + } catch let error { + completion(.failure(error)) + } + } + + func removeAnnotation(jsonAnnotation: String, completion: @escaping (Result) -> Void) { + do { + if document == nil { + let error = PspdfkitApiError(code: "", message: "Error while removing annotation: \(jsonAnnotation)", details: nil) + completion(.failure(error)) + return + } + let success = try PspdfkitFlutterHelper.removeAnnotation(jsonAnnotation, for: document!) + completion(.success(success)) + } catch let error { + completion(.failure(error)) + } + } + + func getAnnotations(pageIndex: Int64, type: String, completion: @escaping (Result) -> Void) { + do { + if document == nil { + let error = PspdfkitApiError(code: "", message: "Error while getting annotations for page: \(pageIndex)", details: nil) + completion(.failure(error)) + return + } + + let annotations = try PspdfkitFlutterHelper.getAnnotations(forPageIndex: PageIndex(pageIndex), andType: type, for: document!) + completion(.success(annotations)) + } catch let error { + completion(.failure(error)) + } + } + + func getAllUnsavedAnnotations(completion: @escaping (Result) -> Void) { + do { + if document == nil { + let error = PspdfkitApiError(code: "", message: "Error while getting all unsaved annotations", details: nil) + completion(.failure(error)) return } - let formFieldJson = FormHelper.convertFormFields(formFields: formFields!) - result(formFieldJson) - break - case "getPageInfo": - if let pageIndex = (call.arguments as? [String: Any])?["pageIndex"] as? Int { - let finalPageIndex = PageIndex(pageIndex) - let pageInfo = self.document?.pageInfoForPage(at: finalPageIndex) - let pageInfoDictionary: [String: Any?] = [ - "width": pageInfo?.size.width, - "height": pageInfo?.size.height, - "rotation": pageInfo?.savedRotation.rawValue, - "index": pageIndex, - "label": document?.pageLabelForPage(at: PageIndex(pageIndex), substituteWithPlainLabel: false) - ] - result(pageInfoDictionary) - } else { - result(FlutterError(code: "InvalidArgument", message: "Invalid page index", details: nil)) - } - break - case "exportPdf": - do { - let filePath = self.document?.fileURL?.path - if ((filePath) == nil){ - result(FlutterError(code: "", message: "", details:nil)) - } - let data = try Data(contentsOf: URL(fileURLWithPath: filePath!)) - let byteArray = data.map { $0 } - result(byteArray) - } catch let error { - result(FlutterError(code: "PdfDocumentError", message: error.localizedDescription, details: nil)) - } - break - case "save": - break - default: - result(FlutterMethodNotImplemented) + + let annotations = try PspdfkitFlutterHelper.getAllUnsavedAnnotations(for: document!) + completion(.success(annotations)) + } catch let error { + completion(.failure(error)) + } + } + + func importXfdf(xfdfString: String, completion: @escaping (Result) -> Void) { + do { + if document == nil { + let error = PspdfkitApiError(code: "", message: "Error while importing xfdf: \(xfdfString)", details: nil) + completion(.failure(error)) + return + } + let success = try PspdfkitFlutterHelper.importXFDF(fromString: xfdfString, for: document!) + completion(.success(success)) + } catch let error { + completion(.failure(error)) + } + } + + func exportXfdf(xfdfPath: String, completion: @escaping (Result) -> Void) { + do { + if document == nil { + let error = PspdfkitApiError(code: "", message: "Error while exporting xfdf: \(xfdfPath)", details: nil) + completion(.failure(error)) + return } + + let bookmark = try PspdfkitFlutterHelper.exportXFDF(toPath: xfdfPath, for: document!) + completion(.success(bookmark)) + } catch let error { + completion(.failure(error)) } + } + + func save(outputPath: String?, options: DocumentSaveOptions?, completion: @escaping (Result) -> Void) { + document?.save() { Result in + if case .success = Result { + completion(.success(true)) + } else { + let error = PspdfkitApiError(code: "", message: "Failed to save PDF document.", details: nil ) + completion(.failure(error)) + } + } + } + + @objc public func register( binaryMessenger: FlutterBinaryMessenger){ + PdfDocumentApiSetup.setUp(binaryMessenger: binaryMessenger, api: self, messageChannelSuffix: document!.uid) + } + + @objc public func unRegister(binaryMessenger: FlutterBinaryMessenger){ + PdfDocumentApiSetup.setUp(binaryMessenger: binaryMessenger, api: nil, messageChannelSuffix: document!.uid); + } } + diff --git a/ios/Classes/PspdfPlatformView.m b/ios/Classes/PspdfPlatformView.m index 6f0bec7b..2a4de64b 100644 --- a/ios/Classes/PspdfPlatformView.m +++ b/ios/Classes/PspdfPlatformView.m @@ -24,6 +24,7 @@ @interface PspdfPlatformView() @property (nonatomic) PSPDFNavigationController *navigationController; @property (nonatomic) FlutterPdfDocument *flutterPdfDocument; @property (nonatomic) NSObject *binaryMessenger; +@property PspdfkitPlatformViewImpl *platformViewImpl; @end @implementation PspdfPlatformView @@ -41,7 +42,9 @@ - (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId argum _navigationController = [PSPDFNavigationController new]; _navigationController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _navigationController.view.frame = frame; - + _platformViewImpl = [[PspdfkitPlatformViewImpl alloc] init]; + [_platformViewImpl registerWithBinaryMessenger:messenger viewId:[NSString stringWithFormat:@"%lld",viewId]]; + // View controller containment _flutterViewController = [UIApplication sharedApplication].delegate.window.rootViewController; if (_flutterViewController == nil) { @@ -114,6 +117,8 @@ - (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId argum __weak id weakSelf = self; + [_platformViewImpl setViewControllerWithController:_pdfViewController]; + [_channel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) { [weakSelf handleMethodCall:call result:result]; }]; @@ -132,7 +137,9 @@ - (void)documentDidFinishRendering { NSDictionary *arguments = @{ @"documentId": documentId, }; - _flutterPdfDocument = [[FlutterPdfDocument alloc] initWithDocument:self.pdfViewController.document messenger: _binaryMessenger]; + _flutterPdfDocument = [[FlutterPdfDocument alloc] initWithViewController:self.pdfViewController]; + [_flutterPdfDocument registerWithBinaryMessenger:_binaryMessenger]; + [_platformViewImpl onDocumentLoadedWithDocumentId:documentId]; [_channel invokeMethod:@"onDocumentLoaded" arguments:arguments]; } } @@ -150,6 +157,10 @@ - (void)dealloc { } - (void)cleanup { + [self.flutterPdfDocument unRegisterWithBinaryMessenger:_binaryMessenger]; + self.flutterPdfDocument = nil; + [self.platformViewImpl unRegisterWithBinaryMessenger:_binaryMessenger]; + self.platformViewImpl = nil; self.pdfViewController.document = nil; [self.pdfViewController.view removeFromSuperview]; [self.pdfViewController removeFromParentViewController]; diff --git a/ios/Classes/PspdfkitApiImpl.swift b/ios/Classes/PspdfkitApiImpl.swift new file mode 100644 index 00000000..685b72f2 --- /dev/null +++ b/ios/Classes/PspdfkitApiImpl.swift @@ -0,0 +1,553 @@ +// +// Copyright © 2024 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 Foundation +import PSPDFKit + +@objc(PspdfkitApiImpl) +public class PspdfkitApiImpl: NSObject, PspdfkitApi, PDFViewControllerDelegate, InstantClientDelegate { + + private let PSPDFSettingKeyHybridEnvironment = SDK.Setting.init(rawValue: "com.pspdfkit.hybrid-environment") + private var pdfViewController: PDFViewController? = nil; + private var messenger: FlutterBinaryMessenger? = nil; + private var pspdfkitApiCallbacks: PspdfkitFlutterApiCallbacks? = nil; + + func getFrameworkVersion(completion: @escaping (Result) -> Void) { + let versionString:String = PSPDFKit.SDK.versionNumber + completion(.success(versionString)) + } + + func setLicenseKey(licenseKey: String?, completion: @escaping (Result) -> Void) { + SDK.setLicenseKey(licenseKey, options: [PSPDFSettingKeyHybridEnvironment:"Flutter"]) + } + + func setLicenseKeys(androidLicenseKey: String?, iOSLicenseKey: String?, webLicenseKey: String?, completion: @escaping (Result) -> Void) { + SDK.setLicenseKey(iOSLicenseKey, options: [PSPDFSettingKeyHybridEnvironment:"Flutter"]) + } + + func present(document: String, configuration: [String : Any]?, completion: @escaping (Result) -> Void) { + let documentPath = document + if documentPath.isEmpty { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Document path may not be nil or empty."]) + completion(.failure(error)) + return + } + + let configurationDictionary = PspdfkitFlutterConverter.processConfigurationOptionsDictionary(forPrefix: configuration ?? [:]) + + guard let document = PspdfkitFlutterHelper.document(fromPath: documentPath) else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Document is missing or invalid."]) + completion(.failure(error)) + return + } + + // Unlock password protected document. + PspdfkitFlutterHelper.unlock( document:document, dictionary: configuration) + + let isImageDocument = PspdfkitFlutterHelper.isImageDocument(documentPath) + let pdfConfiguration = PspdfkitFlutterConverter.configuration(configurationDictionary, isImageDocument: isImageDocument) + + self.pdfViewController = PDFViewController(document: document, configuration: pdfConfiguration) + self.setupViewController(configurationDictionary: configurationDictionary) { result in + // Set measurements value configurations + if let measurementsValue = configurationDictionary["measurementValueConfigurations"] as? [[String: Any]] { + for measurementValue in measurementsValue { + _ = PspdfkitMeasurementConvertor.addMeasurementValueConfiguration(document: self.pdfViewController!.document!, configuration: measurementValue as NSDictionary) + } + } + completion(result) + } + } + + func presentInstant(serverUrl: String, jwt: String, configuration: [String : Any]?, completion: @escaping (Result) -> Void) { + guard !serverUrl.isEmpty else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Server URL path may not be nil or empty."]) + completion(.failure(error)) + return + } + + guard !jwt.isEmpty else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "JWT may not be nil or empty."]) + completion(.failure(error)) + return + } + + let configurationDictionary = PspdfkitFlutterConverter.processConfigurationOptionsDictionary(forPrefix: configuration ?? [:]) + let enableInstantComments = configurationDictionary["enableInstantComments"] as? Bool ?? false + let pdfConfiguration = PspdfkitFlutterConverter.configuration(configurationDictionary, isImageDocument: false) + let documentInfo = InstantDocumentInfo(serverURL: URL(string: serverUrl)!, url: URL(string: serverUrl)!, jwt: jwt) + + do { + let instantViewController = try InstantDocumentViewController(documentInfo: documentInfo, configurations: pdfConfiguration.configurationUpdated { builder in + if enableInstantComments { + var editableAnnotationTypes = builder.editableAnnotationTypes + editableAnnotationTypes!.insert(Annotation.Tool.instantCommentMarker) + builder.editableAnnotationTypes = editableAnnotationTypes + } + }) + self.pdfViewController = instantViewController + + let client = instantViewController.client + client.delegate = self + + self.pdfViewController = instantViewController + self.setupViewController(configurationDictionary: configurationDictionary) { result in + // Set measurements value configuration + if let measurementsValue = configurationDictionary["measurementValueConfigurations"] as? [[String: Any]] { + for measurementValue in measurementsValue { + _ = PspdfkitMeasurementConvertor.addMeasurementValueConfiguration(document: self.pdfViewController!.document!, + configuration: measurementValue as NSDictionary) + } + } + completion(result) + } + } catch { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create InstantDocumentViewController: \(error.localizedDescription)"]) + completion(.failure(error)) + return + } + } + + func setFormFieldValue(value: String, fullyQualifiedName: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + + let success = try PspdfkitFlutterHelper.setFormFieldValue(value, forFieldWithFullyQualifiedName: fullyQualifiedName, for: document) + completion(.success(success)) + } catch { + completion(.failure(error)) + } + } + + func getFormFieldValue(fullyQualifiedName: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + + let value = try PspdfkitFlutterHelper.getFormFieldValue(forFieldWithFullyQualifiedName: fullyQualifiedName, for: document) + completion(.success(value as? String)) + } catch { + completion(.failure(error)) + } + } + + func applyInstantJson(annotationsJson: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + let success = try PspdfkitFlutterHelper.applyInstantJson(annotationsJson: annotationsJson, document: document) + pdfViewController!.reloadData() + completion(.success(success)) + } catch { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to apply Instant JSON: \(error.localizedDescription)"]) + completion(.failure(error)) + } + } + + func exportInstantJson(completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + + let annotationsJson = try PspdfkitFlutterHelper.exportInstantJson(document: document) + completion(.success(annotationsJson)) + } catch { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to export Instant JSON: \(error.localizedDescription)"]) + completion(.failure(error)) + } + } + + func addAnnotation(jsonAnnotation: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + + let success = try PspdfkitFlutterHelper.addAnnotation(jsonAnnotation, for: document) + completion(.success(success)) + } catch { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to add annotation: \(error.localizedDescription)"]) + completion(.failure(error)) + } + } + + func removeAnnotation(jsonAnnotation: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + + let success = try PspdfkitFlutterHelper.removeAnnotation(jsonAnnotation, for: document) + completion(.success(success)) + } catch { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to remove annotation: \(error.localizedDescription)"]) + completion(.failure(error)) + } + } + + func getAnnotations(pageIndex: Int64, type: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + let annotations = try PspdfkitFlutterHelper.getAnnotations(forPageIndex: PageIndex(Int(pageIndex)), andType: type, for: document) + completion(.success(annotations)) + } catch { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to get annotations: \(error.localizedDescription)"]) + completion(.failure(error)) + } + } + + func getAllUnsavedAnnotations(completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + + let annotations = try PspdfkitFlutterHelper.getAllUnsavedAnnotations(for: document) + completion(.success(annotations)) + } catch { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to get all unsaved annotations: \(error.localizedDescription)"]) + completion(.failure(error)) + } + } + + func processAnnotations(type: AnnotationType, processingMode: AnnotationProcessingMode, destinationPath: String, completion: @escaping (Result) -> Void) { + do { + let success = try PspdfkitFlutterHelper.processAnnotations(ofType: "\(type)", withProcessingMode: "\(processingMode)", andDestinationPath: destinationPath, for: pdfViewController!) + completion(.success(success)) + } catch { + completion(.failure(error)) + } + } + + func importXfdf(xfdfString: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + + let success = try PspdfkitFlutterHelper.importXFDF(fromString: xfdfString, for: document) + completion(.success(success)) + } catch { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to import XFDF: \(error.localizedDescription)"]) + completion(.failure(error)) + } + } + + func exportXfdf(xfdfPath: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + + let success = try PspdfkitFlutterHelper.exportXFDF(toPath: xfdfPath, for: document) + completion(.success(success)) + } catch { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to export XFDF: \(error.localizedDescription)"]) + completion(.failure(error)) + } + } + + func save(completion: @escaping (Result) -> Void) { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(NSError(domain: "PspdfkitPlatformViewImpl", code: -1, userInfo: [NSLocalizedDescriptionKey: "PDF document not found or is invalid."]))) + return + } + document.save() { Result in + if case .success = Result { + completion(.success(true)) + } else { + let error = PspdfkitApiError(code: "", message: "Failed to save PDF document.", details: nil ) + completion(.failure(error)) + } + } + } + + func setDelayForSyncingLocalChanges(delay: Double, completion: @escaping (Result) -> Void) { + // if pdfViewController is an instance of InstantDocumentViewController, then we can set the delay. + if let instantDocumentViewController = pdfViewController as? InstantDocumentViewController { + instantDocumentViewController.documentDescriptor.delayForSyncingLocalChanges = delay + completion(.success(true)) + } else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Delay can only be set for Instant documents"]) + completion(.failure(error)) + } + } + + func setListenToServerChanges(listen: Bool, completion: @escaping (Result) -> Void) { + + if let instantDocumentViewController = pdfViewController as? InstantDocumentViewController { + instantDocumentViewController.shouldListenForServerChangesWhenVisible = listen + completion(.success(true)) + } else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "listenToServerChanges can only be set for Instant documents"]) + completion(.failure(error)) + } + } + + func syncAnnotations(completion: @escaping (Result) -> Void) { + // if pdfViewController is an instance of InstantDocumentViewController, then we can set the delay. + if let instantDocumentViewController = pdfViewController as? InstantDocumentViewController { + instantDocumentViewController.documentDescriptor.sync() + completion(.success(true)) + } else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "syncAnnotations can only be called on Instant document"]) + completion(.failure(error)) + } + } + + func setAnnotationPresetConfigurations(configurations: [String : Any?], completion: @escaping (Result) -> Void) { + if let annotationConfigurations = configurations["annotationConfigurations"] as? Dictionary> { + AnnotationsPresetConfigurations.setConfigurations(annotationPreset: annotationConfigurations) + completion(.success(true)) + } else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid annotation configurations."]) + completion(.failure(error)) + } + } + + func getTemporaryDirectory(completion: @escaping (Result) -> Void) { + let paths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true) + if let tempDirectory = paths.first { + completion(.success(tempDirectory)) + } else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Unable to find temporary directory."]) + completion(.failure(error)) + } + } + + func getAuthorName(completion: @escaping (Result) -> Void) { + let authorName = pdfViewController?.document?.defaultAnnotationUsername + completion(.success(authorName ?? "")) + } + + func generatePdf(pages: [[String : Any]], outputPath: String, completion: @escaping (Result) -> Void) { + + let pageAdaptor: PspdfkitPageConvertor = PspdfkitPageConvertor() + let convertedPages = pageAdaptor.convert(pages: pages) + let configuration = Processor.Configuration() + + guard let processedDocumentURL = PspdfkitFlutterHelper.writableFileURL(withPath: outputPath, override: true, copyIfNeeded: true) else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Unable to create output file."]) + completion(.failure(error)) + return + } + + + for (index, page) in convertedPages.enumerated(){ + configuration.addNewPage(at: UInt(index) , configuration: page) + } + + // Save to a new PDF file. + do { + try Processor(configuration: configuration, securityOptions: nil).write(toFileURL: processedDocumentURL) + completion(.success(processedDocumentURL.relativePath)) + } catch { + completion(.failure(error)) + } + } + + func generatePdfFromHtmlString(html: String, outPutFile: String, options: [String : Any]?, completion: @escaping (Result) -> Void) { + + let outputPath = outPutFile + guard let processedDocumentURL = PspdfkitFlutterHelper.writableFileURL(withPath: outputPath, override: true, copyIfNeeded: false) else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Unable to create output file at \(outputPath)."]) + completion(.failure(error)) + return + } + + var generatePdfOptions:[String: Any] = [:] + + if(options?["documentTitle"] != nil){ + generatePdfOptions[PSPDFProcessorDocumentTitleKey] = options?["documentTitle"] + } + + if(options?["numberOfPages"] != nil){ + generatePdfOptions[PSPDFProcessorNumberOfPagesKey] = options?["numberOfPages"] + } + + generatePdfOptions = generatePdfOptions as [String: Any] + + Processor.generatePDF(fromHTMLString: html, outputFileURL: processedDocumentURL, options: generatePdfOptions) { outputURL, error in + if let outputURL = outputURL { + completion(.success(processedDocumentURL.relativePath)) + } else if let error = error { + completion(.failure(error)) + } + } + } + + func generatePdfFromHtmlUri(htmlUri: String, outPutFile: String, options: [String : Any]?, completion: @escaping (Result) -> Void) { + + let htmlURLString = htmlUri + let outputPath = outPutFile + guard let processedDocumentURL = PspdfkitFlutterHelper.writableFileURL(withPath: outputPath, override: true, copyIfNeeded: false) else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Unable to find temporary directory."]) + completion(.failure(error)) + return + } + guard let htmlURL = URL(string: htmlURLString) else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid HTML URL."]) + completion(.failure(error)) + return + } + + var processorOptions: [String: Any] = [:] + + if (options?["numberOfPage"]) != nil { + let numberOfPage = options?["numberOfPage"] as! Int + processorOptions[PSPDFProcessorNumberOfPagesKey] = numberOfPage + } else { + let numberOfPages = 10 + processorOptions[PSPDFProcessorNumberOfPagesKey] = numberOfPages + } + + if (options?["documentTitle"]) != nil { + let documentTitle = options?["documentTitle"] as! String + processorOptions[PSPDFProcessorDocumentTitleKey] = documentTitle + } else { + processorOptions[PSPDFProcessorDocumentTitleKey] = "" + } + + Processor.generatePDF(from:htmlURL,outputFileURL: processedDocumentURL, options: processorOptions) { outputURL, error in + if let outputURL = outputURL { + completion(.success(processedDocumentURL.relativePath)) + } else if let error = error { + completion(.failure(error)) + } + } + } + + public func instantClient(_ instantClient: InstantClient, didFinishDownloadFor documentDescriptor: any InstantDocumentDescriptor) { + pspdfkitApiCallbacks?.onInstantDownloadFinished(documentId: documentDescriptor.identifier){_ in} + + } + + public func instantClient(_ instantClient: InstantClient, documentDescriptor: any InstantDocumentDescriptor, didFailDownloadWithError error: any Error) { + pspdfkitApiCallbacks?.onInstantDownloadFailed(documentId: documentDescriptor.identifier, error: error.localizedDescription){_ in } + } + + public func instantClient(_ instantClient: InstantClient, didFailAuthenticationFor documentDescriptor: any InstantDocumentDescriptor) { + pspdfkitApiCallbacks?.onInstantAuthenticationFailed(documentId: documentDescriptor.identifier, error: "Authentication failed"){_ in } + } + + public func instantClient(_ instantClient: InstantClient, documentDescriptor: any InstantDocumentDescriptor, didFinishReauthenticationWithJWT validJWT: String) { + pspdfkitApiCallbacks?.onInstantAuthenticationFinished(documentId: documentDescriptor.identifier, validJWT: validJWT){_ in} + } + + public func instantClient(_ instantClient: InstantClient, documentDescriptor: any InstantDocumentDescriptor, didFailReauthenticationWithError error: any Error) { + pspdfkitApiCallbacks?.onInstantAuthenticationFailed(documentId: documentDescriptor.identifier, error: error.localizedDescription){_ in } + } + + public func instantClient(_ instantClient: InstantClient, didFinishSyncFor documentDescriptor: any InstantDocumentDescriptor) { + pspdfkitApiCallbacks?.onInstantSyncFinished(documentId: documentDescriptor.identifier){_ in } + } + + public func instantClient(_ instantClient: InstantClient, documentDescriptor: any InstantDocumentDescriptor, didFailSyncWithError error: any Error) { + pspdfkitApiCallbacks?.onInstantSyncFailed(documentId: documentDescriptor.identifier, error: documentDescriptor.identifier){_ in } + } + + public func instantClient(_ instantClient: InstantClient, didBeginSyncFor documentDescriptor: any InstantDocumentDescriptor) { + pspdfkitApiCallbacks?.onInstantSyncStarted(documentId: documentDescriptor.identifier){ _ in} + } + + public func pdfViewControllerWillDismiss(_ pdfController: PDFViewController) { + pspdfkitApiCallbacks?.onPdfViewControllerWillDismiss() { _ in } + } + + public func pdfViewControllerDidDismiss(_ pdfController: PDFViewController) { + pspdfkitApiCallbacks?.onPdfViewControllerDidDismiss(){ _ in } + } + + public func pdfViewController(_ pdfController: PDFViewController, didChange document: Document?) { + if let document { + pspdfkitApiCallbacks?.onDocumentLoaded(documentId: document.uid){ _ in } + } + } + + func setupViewController(configurationDictionary: [AnyHashable: Any], completion: @escaping (Result) -> Void) { + guard let pdfViewController = self.pdfViewController else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "PDFViewController is not initialized."]) + completion(.failure(error)) + return + } + + pdfViewController.appearanceModeManager.appearanceMode = PspdfkitFlutterConverter.appearanceMode(configurationDictionary) + pdfViewController.pageIndex = PspdfkitFlutterConverter.pageIndex(configurationDictionary) + pdfViewController.delegate = self + + if !configurationDictionary.isEmpty { + if let leftBarButtonItems = configurationDictionary["leftBarButtonItems"] as? [String] { + PspdfkitFlutterHelper.setLeftBarButtonItems(leftBarButtonItems, for: pdfViewController) + } + if let rightBarButtonItems = configurationDictionary["rightBarButtonItems"] as? [String] { + PspdfkitFlutterHelper.setRightBarButtonItems(rightBarButtonItems, for: pdfViewController) + } + if let invertColors = configurationDictionary["invertColors"] as? Bool { + pdfViewController.appearanceModeManager.appearanceMode = invertColors ? .night : [] + } + if let toolbarTitle = configurationDictionary["toolbarTitle"] as? String { + PspdfkitFlutterHelper.setToolbarTitle(toolbarTitle, for: pdfViewController) + } + } + + let navigationController = PDFNavigationController(rootViewController: pdfViewController) + navigationController.modalPresentationStyle = .fullScreen + if let presentingViewController = UIApplication.shared.delegate?.window??.rootViewController { + presentingViewController.present(navigationController, animated: true) { + completion(.success(true)) + } + } else { + let error = NSError(domain: "FlutterError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Presenting view controller is not available."]) + completion(.failure(error)) + } + } + + func checkAndroidWriteExternalStoragePermission(completion: @escaping (Result) -> Void) { + completion(.failure(PspdfkitApiError(code: "", message: "Not implements", details: nil))) + } + + func requestAndroidWriteExternalStoragePermission(completion: @escaping (Result) -> Void) { + completion(.failure(PspdfkitApiError(code: "", message: "Not implements", details: nil))) + } + + func openAndroidSettings(completion: @escaping (Result) -> Void) { + completion(.failure(PspdfkitApiError(code: "", message: "Not implements", details: nil))) + } + + // Setup pigeon message channel. + @objc public func register( binaryMessenger: FlutterBinaryMessenger){ + messenger = binaryMessenger + PspdfkitApiSetup.setUp(binaryMessenger: binaryMessenger, api: self, messageChannelSuffix: "pspdfkit") + pspdfkitApiCallbacks = PspdfkitFlutterApiCallbacks(binaryMessenger: binaryMessenger, messageChannelSuffix: "pspdfkit") + } + + // Unregister pigeon message channel. + @objc public func unRegister(){ + if messenger != nil { + PspdfkitApiSetup.setUp(binaryMessenger: messenger!, api: nil) + } + pspdfkitApiCallbacks = nil + } +} diff --git a/ios/Classes/PspdfkitFlutterHelper.m b/ios/Classes/PspdfkitFlutterHelper.m index 67cb1e61..55112173 100644 --- a/ios/Classes/PspdfkitFlutterHelper.m +++ b/ios/Classes/PspdfkitFlutterHelper.m @@ -12,6 +12,7 @@ #import "PspdfkitFlutterConverter.h" #import "pspdfkit_flutter-Swift.h" +#warning "This file is deprecated. Use PspddfkitHelper.swift instead." @implementation PspdfkitFlutterHelper @@ -158,7 +159,7 @@ + (void)processMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result message:@"syncAnnotations can only be called on Instant document" details:nil]); } - }else if ([@"setAnnotationPresetConfigurations" isEqualToString:call.method]) { + }else if ([@"setAnnotationConfigurations" isEqualToString:call.method]) { [AnnotationsPresetConfigurations setConfigurationsWithAnnotationPreset:call.arguments[@"annotationConfigurations"]]; result(nil); } else if ([@"getPageInfo" isEqualToString:call.method]) { diff --git a/ios/Classes/PspdfkitFlutterHelper.swift b/ios/Classes/PspdfkitFlutterHelper.swift new file mode 100644 index 00000000..44219baf --- /dev/null +++ b/ios/Classes/PspdfkitFlutterHelper.swift @@ -0,0 +1,488 @@ +// +// Copyright © 2024 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 Foundation +import PSPDFKit + +// This class contains shared code. +class PspdfkitFlutterHelper: NSObject { + + // MARK: - Document Helpers + + static func document(fromPath path: String) -> Document? { + let url: URL? + + if path.hasPrefix("/") { + url = URL(fileURLWithPath: path) + } else { + url = Bundle.main.url(forResource: path, withExtension: nil) + } + + guard let documentURL = url else { + return nil + } + + if isImageDocument(path) { + return ImageDocument(imageURL: documentURL) + } else { + return Document(url: documentURL) + } + } + + static func isImageDocument(_ path: String) -> Bool { + let fileExtension = path.split(separator: ".").last?.lowercased() + return ["png", "jpeg", "jpg", "tiff", "tif"].contains(fileExtension) + } + + // MARK: - File Helpers + + static func fileURL(withPath path: String) -> URL? { + var expandedPath = path + expandedPath = (expandedPath as NSString).expandingTildeInPath + expandedPath = expandedPath.replacingOccurrences(of: "file:", with: "") + if !(expandedPath as NSString).isAbsolutePath { + let docsFolder = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + expandedPath = (docsFolder as NSString).appendingPathComponent(expandedPath, conformingTo: UTType.fileURL) + } + return URL(fileURLWithPath: expandedPath) + } + + static func writableFileURL(withPath path: String, override: Bool, copyIfNeeded: Bool) -> URL? { + let writableFileURL: URL + if (path as NSString).isAbsolutePath { + writableFileURL = URL(fileURLWithPath: path) + } else { + let docsFolder = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + writableFileURL = URL(fileURLWithPath: (docsFolder as NSString).appendingPathComponent(path)) + } + + let fileManager = FileManager.default + if override { + try? fileManager.removeItem(at: writableFileURL) + } + + if !fileManager.fileExists(atPath: writableFileURL.path) { + do { + try fileManager.createDirectory(atPath: (writableFileURL.path as NSString).deletingLastPathComponent, withIntermediateDirectories: true, attributes: nil) + } catch { + print("Failed to create directory: \(error.localizedDescription)") + return nil + } + + if copyIfNeeded, let fileURL = fileURL(withPath: path), fileManager.fileExists(atPath: fileURL.path) { + do { + try fileManager.copyItem(at: fileURL, to: writableFileURL) + } catch { + print("Failed to copy item at URL '\(path)' with error: \(error.localizedDescription)") + return nil + } + } + } + return writableFileURL + } + + // MARK: - Password Helper + + static func unlock(document: Document, dictionary: [String: Any]?) { + guard let dictionary = dictionary, !dictionary.isEmpty else { + return + } + if let password = dictionary["password"] as? String, !password.isEmpty { + document.unlock(withPassword: password) + } + } + + // MARK: - Toolbar Customization + + static func setToolbarTitle(_ toolbarTitle: String?, for pdfViewController: PDFViewController) { + guard let toolbarTitle = toolbarTitle else { + return + } + pdfViewController.title = toolbarTitle + } + + static func setLeftBarButtonItems(_ items: [String]?, for pdfViewController: PDFViewController) { + guard let items = items, !items.isEmpty else { + return + } + var leftItems = [UIBarButtonItem]() + for barButtonItemString in items { + if let barButtonItem = barButtonItem(fromString: barButtonItemString, for: pdfViewController), + ((pdfViewController.navigationItem.rightBarButtonItems?.contains(barButtonItem)) == nil) { + leftItems.append(barButtonItem) + } + } + pdfViewController.navigationItem.setLeftBarButtonItems(leftItems, animated: false) + } + + static func setRightBarButtonItems(_ items: [String]?, for pdfViewController: PDFViewController) { + guard let items = items, !items.isEmpty else { + return + } + var rightItems = [UIBarButtonItem]() + for barButtonItemString in items { + if let barButtonItem = barButtonItem(fromString: barButtonItemString, for: pdfViewController), + ((pdfViewController.navigationItem.leftBarButtonItems?.contains(barButtonItem)) == nil) { + rightItems.append(barButtonItem) + } + } + pdfViewController.navigationItem.setRightBarButtonItems(rightItems, animated: false) + } + + static func barButtonItem(fromString barButtonItem: String, for pdfViewController: PDFViewController) -> UIBarButtonItem? { + switch barButtonItem { + case "closeButtonItem": + return pdfViewController.closeButtonItem + case "outlineButtonItem": + return pdfViewController.outlineButtonItem + case "searchButtonItem": + return pdfViewController.searchButtonItem + case "thumbnailsButtonItem": + return pdfViewController.thumbnailsButtonItem + case "documentEditorButtonItem": + return pdfViewController.documentEditorButtonItem + case "printButtonItem": + return pdfViewController.printButtonItem + case "openInButtonItem": + return pdfViewController.openInButtonItem + case "emailButtonItem": + return pdfViewController.emailButtonItem + case "messageButtonItem": + return pdfViewController.messageButtonItem + case "annotationButtonItem": + return pdfViewController.annotationButtonItem + case "bookmarkButtonItem": + return pdfViewController.bookmarkButtonItem + case "brightnessButtonItem": + return pdfViewController.brightnessButtonItem + case "activityButtonItem": + return pdfViewController.activityButtonItem + case "settingsButtonItem": + return pdfViewController.settingsButtonItem + case "readerViewButtonItem": + return pdfViewController.readerViewButtonItem + default: + return nil + } + } + + // MARK: - Forms + + static func setFormFieldValue(_ value: String, forFieldWithFullyQualifiedName fullyQualifiedName: String, for document: Document) throws -> Bool { + + guard !fullyQualifiedName.isEmpty else { + throw PspdfkitApiError(code: "", message:"Fully qualified name may not be nil or empty." , details: nil) + } + + var success = false + for formElement in document.formParser?.forms ?? [] { + if formElement.fullyQualifiedFieldName == fullyQualifiedName { + if let buttonFormElement = formElement as? ButtonFormElement { + if value == "selected" { + buttonFormElement.select() + success = true + } else if value == "deselected" { + buttonFormElement.deselect() + success = true + } + } else if let choiceFormElement = formElement as? ChoiceFormElement { + choiceFormElement.selectedIndices = IndexSet(integer: Int(value) ?? 0) + success = true + } else if let textFieldFormElement = formElement as? TextFieldFormElement { + textFieldFormElement.contents = value + success = true + } else if formElement is SignatureFormElement { + throw PspdfkitApiError(code: "", message: "Signature form elements cannot be modified.", details: nil) + } else { + return false + } + break + } + } + + if !success { + throw PspdfkitApiError(code: "", message: "Error while searching for a form element with name \(fullyQualifiedName).", details: nil) + } + return true + } + + static func getFormFieldValue(forFieldWithFullyQualifiedName fullyQualifiedName: String, for document: Document) throws -> Any { + guard !fullyQualifiedName.isEmpty else { + throw PspdfkitApiError(code: "", message: "Fully qualified name may not be nil or empty.", details : nil) + } + + for formElement in document.formParser?.forms ?? [] { + if formElement.fullyQualifiedFieldName == fullyQualifiedName { + if formElement.value != nil { + return formElement.value! + } else { + throw PspdfkitApiError(code: "", message: "Error while searching for a form element with name \(fullyQualifiedName).", details: nil) + } + } + } + + throw PspdfkitApiError(code: "", message: "Error while searching for a form element with name \(fullyQualifiedName).", details : nil) + } + + static func getFormFields(for document: Document) throws -> [[String : Any]]{ + let formFields = document.formParser?.forms ?? [] + let data:[[String : Any]] = FormHelper.convertFormFields(formFields: formFields) as! [[String : Any]] + if formFields.isEmpty { + throw PspdfkitApiError(code: "", message: "No form fields found in the document.", details: nil) + } + return data + } + + // MARK: - Annotation Processing + + static func processAnnotations(ofType type: String, withProcessingMode processingMode: String, andDestinationPath destinationPath: String, for pdfViewController: PDFViewController) throws -> Bool { + let change = PspdfkitFlutterConverter.annotationChange(from: processingMode) + guard let processedDocumentURL = writableFileURL(withPath: destinationPath, override: true, copyIfNeeded: false) else { + throw PspdfkitApiError(code: "", message: "Could not create a new PDF file at the given path.", details : nil) + } + + guard let document = pdfViewController.document, document.isValid else { + throw PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details : nil) + } + + let configuration = Processor.Configuration(document: document) + configuration?.modifyAnnotations(ofTypes: PspdfkitFlutterConverter.annotationType(from: type), change: change) + + if configuration == nil { + throw PspdfkitApiError(code: "", message: "Invalid annotation type.", details : nil) + } + + let processor = Processor(configuration: configuration!, securityOptions: nil) + do { + try processor.write(toFileURL: processedDocumentURL) + } catch { + throw PspdfkitApiError(code: "", message: "Error writing to PDF file.", details : error.localizedDescription) + } + + return true + } + + // MARK: - Instant JSON + + static func addAnnotation(_ jsonAnnotation: Any, for document: Document) throws -> Bool { + + let data: Data? + if let jsonString = jsonAnnotation as? String { + data = jsonString.data(using: .utf8) + } else if let jsonDict = jsonAnnotation as? [String: Any] { + data = try? JSONSerialization.data(withJSONObject: jsonDict, options: []) + } else { + throw PspdfkitApiError(code: "", message: "Invalid JSON Annotation.", details : nil) + } + + guard let annotationData = data else { + throw PspdfkitApiError(code: "", message: "Invalid JSON Annotation.", details: nil) + } + + let documentProvider = document.documentProviders.first! + let annotation = try? Annotation(fromInstantJSON: annotationData, documentProvider: documentProvider) + if annotation == nil { + throw PspdfkitApiError(code: "", message: "Failed to create annotation from JSON.", details: nil) + } + + let success = document.add(annotations: [annotation!], options: nil) + if !success { + throw PspdfkitApiError(code: "", message: "Failed to add annotation.", details: nil) + } + + return true + } + + static func removeAnnotation(_ jsonAnnotation: Any, for document: Document) throws -> Bool { + + var annotationUUID: String? + + if let jsonString = jsonAnnotation as? String { + if let jsonData = jsonString.data(using: .utf8), + let jsonDict = try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) as? [String: Any] { + annotationUUID = jsonDict["uuid"] as? String + } + } else if let jsonDict = jsonAnnotation as? [String: Any] { + annotationUUID = jsonDict["uuid"] as? String + } + + guard let uuid = annotationUUID, !uuid.isEmpty else { + throw PspdfkitApiError(code: "", message: "Invalid annotation UUID.", details: nil) + } + + let allAnnotations = document.allAnnotations(of: .all).values.flatMap { $0 } + for annotation in allAnnotations { + if annotation.uuid == uuid { + let success = document.remove(annotations: [annotation], options: nil) + return success + } + } + + return false + } + + static func getAnnotations(forPageIndex pageIndex: PageIndex, andType typeString: String, for document: Document) throws -> Any { + let type = annotationType(from: typeString) + let annotations = document.annotations(at: pageIndex, type: type) + let annotationsJSON = PspdfkitFlutterConverter.instantJSON(from: annotations) + + if annotationsJSON != nil { + return annotationsJSON + } else { + throw PspdfkitApiError(code:"", message: "Failed to get annotations.", details:nil) + } + } + + static func getAllUnsavedAnnotations(for document: Document) throws -> Any { + let documentProvider = document.documentProviders.first! + let data = try document.generateInstantJSON(from: documentProvider, version: .v2) + let annotationsJSON = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] + + if let annotationsJSON = annotationsJSON { + return annotationsJSON + } else { + throw PspdfkitApiError(code:"", message: "Failed to get annotations.", details:nil) + } + } + + // MARK: - XFDF + + static func importXFDF(fromString stringData: String, for document: Document) throws -> Bool { + // convert string into a temporary file. + let fileURL = try stringDataToFile(stringData) + + let dataProvider = FileDataProvider(fileURL: fileURL) + let parser = XFDFParser(dataProvider: dataProvider, documentProvider: document.documentProviders[0]) + + do { + try parser.parse() + let annotations = parser.annotations + document.add(annotations: annotations, options: nil) + // clean up temp file. + _ = try? FileManager.default.removeItem(at: fileURL) + return true + } catch { + throw PspdfkitApiError(code: "", message: "Error while parsing XFDF file.", details: error.localizedDescription ) + } + } + + static func exportXFDF(toPath path: String, for document: Document)throws -> Bool { + guard let fileURL = writableFileURL(withPath: path, override: true, copyIfNeeded: false) else { + throw PspdfkitApiError(code: "", message: "Could not create a new XFDF file at the given path.", details: nil) + } + + var annotations = [Annotation]() + for pageAnnotations in document.allAnnotations(of: .all).values { + annotations.append(contentsOf: pageAnnotations) + } + + do { + let dataSink = try FileDataSink(fileURL: fileURL, options: []) + try XFDFWriter().write(annotations, to: dataSink, documentProvider: document.documentProviders[0]) + } catch { + throw PspdfkitApiError(code: "", message: "Error while exporting XFDF file.", details: error.localizedDescription) + } + + return true + } + + static func applyInstantJson(annotationsJson: String, document: Document) throws -> Bool { + guard let jsonData = annotationsJson.data(using: .utf8) else { + print("Invalid JSON data.") + throw PspdfkitApiError(code: "", message: "Invalid JSON data.", details : nil) + } + + let jsonContainer = DataContainerProvider(data: jsonData) + do { + try document.applyInstantJSON(fromDataProvider: jsonContainer, to: document.documentProviders.first!, lenient: false) + return true + } catch { + print("Error while importing document Instant JSON: \(error.localizedDescription)") + throw PspdfkitApiError(code: "", message: "Error while importing document Instant JSON.", details: error.localizedDescription) + } + } + + static func exportInstantJson(document: Document) throws -> String { + do { + let data = try document.generateInstantJSON(from: document.documentProviders.first!) + if let annotationsJson = String(data: data, encoding: .utf8) { + return annotationsJson + } else { + throw PspdfkitApiError(code: "", message: "Error while exporting document Instant JSON.", details: nil) + } + } catch { + throw PspdfkitApiError(code: "", message: "Error while exporting document Instant JSON.", details: error.localizedDescription) + } + } + + static func annotationType(from typeString: String) -> Annotation.Type { + switch typeString { + case "ink": + return InkAnnotation.self + case "link": + return LinkAnnotation.self + case "highlight": + return HighlightAnnotation.self + case "squiggly": + return SquigglyAnnotation.self + case "strikeout": + return StrikeOutAnnotation.self + case "underline": + return UnderlineAnnotation.self + case "note": + return NoteAnnotation.self + case "ellipse": + return CircleAnnotation.self + case "line": + return LineAnnotation.self + case "polygon": + return PolygonAnnotation.self + case "square": + return SquareAnnotation.self + case "text": + return FreeTextAnnotation.self + case "circle": + return CircleAnnotation.self + case "redact": + return RedactionAnnotation.self + case "stamp": + return StampAnnotation.self + case "caret": + return CaretAnnotation.self + case "popup": + return PopupAnnotation.self + case "file": + return FileAnnotation.self + case "sound": + return SoundAnnotation.self + case "widget": + return WidgetAnnotation.self + case "screen": + return ScreenAnnotation.self + case "richMedia": + return RichMediaAnnotation.self + case "all": + return Annotation.self + default: + return Annotation.self + } + } + + private static func stringDataToFile(_ stringData: String) throws -> URL { + do { + let stringData = stringData.data(using: .utf8)! + let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("temp.txt") + try stringData.write(to: fileURL) + return fileURL + } catch { + throw PspdfkitApiError(code: "PSPDFKIT_ERROR_FILE_WRITE", message: "Failed to write temporary file", details: nil) + } + } + +} diff --git a/ios/Classes/PspdfkitHtmlPdfConvertor.swift b/ios/Classes/PspdfkitHtmlPdfConvertor.swift index 479fefa9..21d89a48 100644 --- a/ios/Classes/PspdfkitHtmlPdfConvertor.swift +++ b/ios/Classes/PspdfkitHtmlPdfConvertor.swift @@ -11,6 +11,7 @@ import Foundation import PSPDFKit.PSPDFProcessor @objc(PspdfkitHtmlPdfConvertor) +@available(*, deprecated, message: "This class is deprecated and will be removed in a future release. Use PspdfkitApiImpl instead.") public class PspdfkitHtmlPdfConvertor: NSObject { @objc public static func generateFromHtmlString(html: String, outputFileURL: URL, convertionOptions: Dictionary?, results:@escaping FlutterResult) { diff --git a/ios/Classes/PspdfkitPdfGenerator.swift b/ios/Classes/PspdfkitPdfGenerator.swift index 045ce141..2467e1db 100644 --- a/ios/Classes/PspdfkitPdfGenerator.swift +++ b/ios/Classes/PspdfkitPdfGenerator.swift @@ -11,6 +11,7 @@ import Foundation import PSPDFKit.PSPDFProcessor @objc(PspdfkitPdfGenerator) +@available(*, deprecated, message: "This class is deprecated and will be removed in a future release. Use PspdfkitApiImpl instead.") public class PspdfkitPdfGenerator: NSObject { static let pageAdaptor: PspdfkitPageConvertor = PspdfkitPageConvertor() diff --git a/ios/Classes/PspdfkitPlatformViewImpl.swift b/ios/Classes/PspdfkitPlatformViewImpl.swift new file mode 100644 index 00000000..06c5b11c --- /dev/null +++ b/ios/Classes/PspdfkitPlatformViewImpl.swift @@ -0,0 +1,245 @@ +// +// Copyright © 2024 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 Foundation + +@objc(PspdfkitPlatformViewImpl) +public class PspdfkitPlatformViewImpl: NSObject, PspdfkitWidgetControllerApi, PDFViewControllerDelegate { + + private var pdfViewController: PDFViewController? = nil; + private var pspdfkitWidgetCallbacks: PspdfkitWidgetCallbacks? = nil; + private var viewId: String? = nil; + + @objc public func setViewController(controller: PDFViewController){ + self.pdfViewController = controller + self.pdfViewController?.delegate = self + } + + public func pdfViewController(_ pdfController: PDFViewController, didChange document: Document?) { + if document != nil { + pspdfkitWidgetCallbacks?.onDocumentLoaded(documentId: document!.uid){ _ in } + } else { + pspdfkitWidgetCallbacks?.onDocumentError(documentId: "", error: "Laoding Document failed") {_ in } + } + } + + public func pdfViewController(_ pdfController: PDFViewController, willBeginDisplaying pageView: PDFPageView, forPageAt pageIndex: Int) { + guard let document = pdfViewController?.document else { + return + } + pspdfkitWidgetCallbacks?.onPageChanged(documentId:document.uid , pageIndex: Int64(pageIndex)){ _ in } + } + + func setFormFieldValue(value: String, fullyQualifiedName: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + let success = try PspdfkitFlutterHelper.setFormFieldValue(value, forFieldWithFullyQualifiedName: fullyQualifiedName, for: document) + completion(.success(success)) + } catch { + completion(.failure(error)) + } + } + + func getFormFieldValue(fullyQualifiedName: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + let value = try PspdfkitFlutterHelper.getFormFieldValue(forFieldWithFullyQualifiedName: fullyQualifiedName, for: document) + completion(.success(value as? String)) + } catch { + completion(.failure(error)) + } + } + + func applyInstantJson(annotationsJson: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + let success = try PspdfkitFlutterHelper.applyInstantJson(annotationsJson: annotationsJson, document: document) + pdfViewController!.reloadData() + completion(.success(success)) + } catch { + completion(.failure(error)) + } + } + + func exportInstantJson(completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + let json = try PspdfkitFlutterHelper.exportInstantJson(document: document) + completion(.success(json)) + } catch { + completion(.failure(error)) + } + } + + func addAnnotation(jsonAnnotation: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + let success = try PspdfkitFlutterHelper.addAnnotation(jsonAnnotation, for: document) + completion(.success(success)) + } catch { + completion(.failure(error)) + } + } + + func removeAnnotation(jsonAnnotation: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + let success = try PspdfkitFlutterHelper.removeAnnotation(jsonAnnotation, for: document) + completion(.success(success)) + } catch { + completion(.failure(error)) + } + } + + func getAnnotations(pageIndex: Int64, type: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + let annotations = try PspdfkitFlutterHelper.getAnnotations(forPageIndex: PageIndex(pageIndex), andType: type, for: document) + completion(.success(annotations)) + } catch { + completion(.failure(error)) + } + } + + func getAllUnsavedAnnotations(completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + let annotations = try PspdfkitFlutterHelper.getAllUnsavedAnnotations(for: document) + completion(.success(annotations)) + } catch { + completion(.failure(error)) + } + } + + func processAnnotations(type: AnnotationType, processingMode: AnnotationProcessingMode, destinationPath: String, completion: @escaping (Result) -> Void) { + do { + let success = try PspdfkitFlutterHelper.processAnnotations(ofType: "\(type)", withProcessingMode: "\(processingMode)", andDestinationPath: destinationPath, for: pdfViewController!) + completion(.success(success)) + } catch { + completion(.failure(error)) + } + } + + func importXfdf(xfdfString: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + let success = try PspdfkitFlutterHelper.importXFDF(fromString: xfdfString, for: document) + completion(.success(success)) + } catch { + completion(.failure(error)) + } + } + + func exportXfdf(xfdfPath: String, completion: @escaping (Result) -> Void) { + do { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "PDF document not found or is invalid.", details: nil))) + return + } + let success = try PspdfkitFlutterHelper.exportXFDF(toPath: xfdfPath, for: document) + completion(.success(success)) + } catch { + completion(.failure(error)) + } + } + + func save(completion: @escaping (Result) -> Void) { + guard let document = pdfViewController?.document, document.isValid else { + completion(.failure(PspdfkitApiError(code: "", message: "Invalid PDF document.", details: nil ))) + return + } + document.save() { Result in + if case .success = Result { + completion(.success(true)) + } else { + let error = PspdfkitApiError(code: "", message: "Failed to save PDF document.", details: nil ) + completion(.failure(error)) + } + } + } + + func setAnnotationConfigurations(configurations: [String : [String : Any]], completion: @escaping (Result) -> Void) { + AnnotationsPresetConfigurations.setConfigurations(annotationPreset: configurations) + } + + func getVisibleRect(pageIndex: Int64, completion: @escaping (Result) -> Void) { + guard let pdfViewController = pdfViewController else { + completion(.failure(NSError(domain: "PspdfkitPlatformViewImpl", code: -1, userInfo: [NSLocalizedDescriptionKey: "PDFViewController is not set."]))) + return + } + let visibleRect = pdfViewController.viewState?.viewPort + + if visibleRect == nil { + completion(.failure(NSError(domain: "PspdfkitPlatformViewImpl", code: -1, userInfo: [NSLocalizedDescriptionKey: "Visible rect is not set."]))) + return + } + + let result: PdfRect = PdfRect(x: visibleRect!.origin.x, y: visibleRect!.origin.y, width: visibleRect!.size.width, height: visibleRect!.size.height) + completion(.success(result)) + } + + func zoomToRect(pageIndex: Int64, rect: PdfRect, animated: Bool?, duration: Double?, completion: @escaping (Result) -> Void) { + guard let pdfViewController = pdfViewController else { + completion(.failure(NSError(domain: "PspdfkitPlatformViewImpl", code: -1, userInfo: [NSLocalizedDescriptionKey: "PDFViewController is not set."]))) + return + } + + let rectToZoom = CGRect(x: rect.x, y: rect.y, width: rect.width, height: rect.height) + pdfViewController.documentViewController?.zoom(toPDFRect: rectToZoom, forPageAt: Int(pageIndex), animated: animated ?? true) + completion(.success(true)) + } + + func getZoomScale(pageIndex: Int64, completion: @escaping (Result) -> Void) { + // Not implemented for iOS. + let errormessage: String = "Not implemented for iOS." + completion(.failure(PspdfkitApiError(code: "", message: errormessage, details: nil))) + } + + @objc public func onDocumentLoaded(documentId: String){ + pspdfkitWidgetCallbacks?.onDocumentLoaded(documentId: documentId){_ in } + } + + @objc public func register( binaryMessenger: FlutterBinaryMessenger, viewId: String){ + self.viewId = viewId + pspdfkitWidgetCallbacks = PspdfkitWidgetCallbacks(binaryMessenger: binaryMessenger, messageChannelSuffix: "widget.callbacks.\(viewId)") + PspdfkitWidgetControllerApiSetup.setUp(binaryMessenger: binaryMessenger, api: self, messageChannelSuffix:viewId) + } + + @objc public func unRegister(binaryMessenger: FlutterBinaryMessenger){ + pspdfkitWidgetCallbacks = nil + PspdfkitWidgetControllerApiSetup.setUp(binaryMessenger: binaryMessenger, api: nil, messageChannelSuffix: viewId ?? "") + } +} diff --git a/ios/Classes/PspdfkitPlugin.m b/ios/Classes/PspdfkitPlugin.m index 79c24869..1b4adb63 100644 --- a/ios/Classes/PspdfkitPlugin.m +++ b/ios/Classes/PspdfkitPlugin.m @@ -21,6 +21,7 @@ @interface PspdfkitPlugin() @property (nonatomic) PSPDFViewController *pdfViewController; +@property PspdfkitApiImpl *apiImpl; @end @implementation PspdfkitPlugin @@ -34,6 +35,9 @@ + (void)registerWithRegistrar:(NSObject*)registrar { channel = [FlutterMethodChannel methodChannelWithName:@"com.pspdfkit.global" binaryMessenger:[registrar messenger]]; PspdfkitPlugin* instance = [[PspdfkitPlugin alloc] init]; [registrar addMethodCallDelegate:instance channel:channel]; + // Register pigeon APIs. + instance.apiImpl = [[PspdfkitApiImpl alloc] init]; + [instance.apiImpl registerWithBinaryMessenger:[registrar messenger]]; } - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { @@ -79,7 +83,7 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { NSArray *measurementsValue = configurationDictionary[@"measurementValueConfigurations"]; if (measurementsValue != nil) { for (NSDictionary *measurementValue in measurementsValue) { - [ PspdfkitMeasurementConvertor addMeasurementValueConfigurationWithDocument:self.pdfViewController .document configuration: measurementValue]; + [PspdfkitMeasurementConvertor addMeasurementValueConfigurationWithDocument:self.pdfViewController .document configuration: measurementValue]; } } @@ -126,7 +130,7 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { NSArray *measurementsValue = configurationDictionary[@"measurementValueConfigurations"]; if (measurementsValue != nil) { for (NSDictionary *measurementValue in measurementsValue) { - [ PspdfkitMeasurementConvertor addMeasurementValueConfigurationWithDocument:self.pdfViewController .document configuration: measurementValue]; + [PspdfkitMeasurementConvertor addMeasurementValueConfigurationWithDocument:self.pdfViewController .document configuration: measurementValue]; } } @@ -174,6 +178,12 @@ - (void) setupViewController:(NSDictionary *)configurationDictionary result:(Flu result(@(YES)); } +- (void) detachFromEngineForRegistrar:(NSObject*)registrar { + // Unregister the API implementation. + [_apiImpl unRegister]; + _apiImpl = nil; +} + - (NSString*)getTemporaryDirectory { NSArray* paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); return paths.firstObject; @@ -243,6 +253,7 @@ - (void)instantClient:(nonnull PSPDFInstantClient *)instantClient documentDescri - (void)dealloc { self.pdfViewController = nil; + self.apiImpl = nil; } @end diff --git a/ios/Classes/api/PspdfkitApi.g.swift b/ios/Classes/api/PspdfkitApi.g.swift new file mode 100644 index 00000000..cd97a1a2 --- /dev/null +++ b/ios/Classes/api/PspdfkitApi.g.swift @@ -0,0 +1,2141 @@ +// Copyright © 2024 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. +// Autogenerated from Pigeon (v22.5.0), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +import Foundation + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#else + #error("Unsupported platform.") +#endif + +/// Error class for passing custom error details to Dart side. +final class PspdfkitApiError: Error { + let code: String + let message: String? + let details: Any? + + init(code: String, message: String?, details: Any?) { + self.code = code + self.message = message + self.details = details + } + + var localizedDescription: String { + return + "PspdfkitApiError(code: \(code), message: \(message ?? ""), details: \(details ?? "")" + } +} + +private func wrapResult(_ result: Any?) -> [Any?] { + return [result] +} + +private func wrapError(_ error: Any) -> [Any?] { + if let pigeonError = error as? PspdfkitApiError { + return [ + pigeonError.code, + pigeonError.message, + pigeonError.details, + ] + } + if let flutterError = error as? FlutterError { + return [ + flutterError.code, + flutterError.message, + flutterError.details, + ] + } + return [ + "\(error)", + "\(type(of: error))", + "Stacktrace: \(Thread.callStackSymbols)", + ] +} + +private func createConnectionError(withChannelName channelName: String) -> PspdfkitApiError { + return PspdfkitApiError(code: "channel-error", message: "Unable to establish connection on channel: '\(channelName)'.", details: "") +} + +private func isNullish(_ value: Any?) -> Bool { + return value is NSNull || value == nil +} + +private func nilOrValue(_ value: Any?) -> T? { + if value is NSNull { return nil } + return value as! T? +} + +enum AndroidPermissionStatus: Int { + case notDetermined = 0 + case denied = 1 + case authorized = 2 + case deniedNeverAsk = 3 +} + +/// Represents the native annotation type. +enum AnnotationType: Int { + case all = 0 + case none = 1 + case undefined = 2 + case link = 3 + case highlight = 4 + case strikeout = 5 + case underline = 6 + case squiggly = 7 + case freeText = 8 + case ink = 9 + case square = 10 + case circle = 11 + case line = 12 + case note = 13 + case stamp = 14 + case caret = 15 + case richMedia = 16 + case screen = 17 + case widget = 18 + case file = 19 + case sound = 20 + case polygon = 21 + case polyline = 22 + case popup = 23 + case watermark = 24 + case trapNet = 25 + case type3d = 26 + case redact = 27 +} + +enum AnnotationTool: Int { + case inkPen = 0 + case inkMagic = 1 + case inkHighlighter = 2 + case freeText = 3 + case freeTextCallOut = 4 + case stamp = 5 + case image = 6 + case highlight = 7 + case underline = 8 + case squiggly = 9 + case strikeOut = 10 + case line = 11 + case arrow = 12 + case square = 13 + case circle = 14 + case polygon = 15 + case polyline = 16 + case eraser = 17 + case cloudy = 18 + case link = 19 + case caret = 20 + case richMedia = 21 + case screen = 22 + case file = 23 + case widget = 24 + case redaction = 25 + case signature = 26 + case stampImage = 27 + case note = 28 + case sound = 29 + case measurementAreaRect = 30 + case measurementAreaPolygon = 31 + case measurementAreaEllipse = 32 + case measurementPerimeter = 33 + case measurementDistance = 34 +} + +enum AnnotationToolVariant: Int { + case inkPen = 0 + case inkMagic = 1 + case inkHighlighter = 2 + case freeText = 3 + case freeTextCallOut = 4 + case stamp = 5 + case image = 6 + case highlight = 7 + case underline = 8 +} + +enum AnnotationProcessingMode: Int { + case flatten = 0 + case remove = 1 + case embed = 2 + case print = 3 +} + +enum DocumentPermissions: Int { + /// Allow printing of document. + case printing = 0 + /// Modify the contents of the document. + case modification = 1 + /// Copy text and images from the document. + case extract = 2 + /// Add or modify text annotations, fill in interactive form fields. + case annotationsAndForms = 3 + /// Fill in existing interactive form fields (including signature fields). + case fillForms = 4 + /// Extract text and images from the document. + case extractAccessibility = 5 + /// Assemble the document (insert, rotate, or delete pages and create document outline items or thumbnail images). + case assemble = 6 + /// Print high quality. + case printHighQuality = 7 +} + +/// The PDF version of a document. +enum PdfVersion: Int { + case pdf10 = 0 + case pdf11 = 1 + case pdf12 = 2 + case pdf13 = 3 + case pdf14 = 4 + case pdf15 = 5 + case pdf16 = 6 + case pdf17 = 7 +} + +enum PdfFormFieldTypes: Int { + case text = 0 + case checkbox = 1 + case radioButton = 2 + case comboBox = 3 + case listBox = 4 + case signature = 5 + case button = 6 + case unknown = 7 +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PdfRect { + var x: Double + var y: Double + var width: Double + var height: Double + + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PdfRect? { + let x = pigeonVar_list[0] as! Double + let y = pigeonVar_list[1] as! Double + let width = pigeonVar_list[2] as! Double + let height = pigeonVar_list[3] as! Double + + return PdfRect( + x: x, + y: y, + width: width, + height: height + ) + } + func toList() -> [Any?] { + return [ + x, + y, + width, + height, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PageInfo { + /// The index of the page. This is a zero-based index. + var pageIndex: Int64 + /// The height of the page in points. + var height: Double + /// The width of the page in points. + var width: Double + /// The rotation of the page in degrees. + var rotation: Int64 + /// The label of the page. + var label: String + + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PageInfo? { + let pageIndex = pigeonVar_list[0] as! Int64 + let height = pigeonVar_list[1] as! Double + let width = pigeonVar_list[2] as! Double + let rotation = pigeonVar_list[3] as! Int64 + let label = pigeonVar_list[4] as! String + + return PageInfo( + pageIndex: pageIndex, + height: height, + width: width, + rotation: rotation, + label: label + ) + } + func toList() -> [Any?] { + return [ + pageIndex, + height, + width, + rotation, + label, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct DocumentSaveOptions { + /// The password is used to encrypt the document. On Web, it's used as the user password. + var userPassword: String? = nil + /// The owner password is used to encrypt the document and set permissions. It's only used on Web. + var ownerPassword: String? = nil + /// Flatten annotations and form fields into the page content. + var flatten: Bool? = nil + /// Whether to save the document incrementally. + var incremental: Bool? = nil + /// The permissions to set on the document. See [DocumentPermissions] for more information. + var permissions: [DocumentPermissions?]? = nil + /// The PDF version to save the document as. + var pdfVersion: PdfVersion? = nil + /// Whether to exclude annotations from the exported document. + var excludeAnnotations: Bool? = nil + /// Whether to exclude annotations that have the noPrint flag set to true from the exported document (Standalone only) + var saveForPrinting: Bool? = nil + /// Whether to include comments in the exported document (Server-Backed only). + var includeComments: Bool? = nil + /// Whether tp allow you to export a PDF in PDF/A format. + var outputFormat: Any? = nil + /// Whether to optimize the document for the web. + var optimize: Bool? = nil + + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> DocumentSaveOptions? { + let userPassword: String? = nilOrValue(pigeonVar_list[0]) + let ownerPassword: String? = nilOrValue(pigeonVar_list[1]) + let flatten: Bool? = nilOrValue(pigeonVar_list[2]) + let incremental: Bool? = nilOrValue(pigeonVar_list[3]) + let permissions: [DocumentPermissions?]? = nilOrValue(pigeonVar_list[4]) + let pdfVersion: PdfVersion? = nilOrValue(pigeonVar_list[5]) + let excludeAnnotations: Bool? = nilOrValue(pigeonVar_list[6]) + let saveForPrinting: Bool? = nilOrValue(pigeonVar_list[7]) + let includeComments: Bool? = nilOrValue(pigeonVar_list[8]) + let outputFormat: Any? = pigeonVar_list[9] + let optimize: Bool? = nilOrValue(pigeonVar_list[10]) + + return DocumentSaveOptions( + userPassword: userPassword, + ownerPassword: ownerPassword, + flatten: flatten, + incremental: incremental, + permissions: permissions, + pdfVersion: pdfVersion, + excludeAnnotations: excludeAnnotations, + saveForPrinting: saveForPrinting, + includeComments: includeComments, + outputFormat: outputFormat, + optimize: optimize + ) + } + func toList() -> [Any?] { + return [ + userPassword, + ownerPassword, + flatten, + incremental, + permissions, + pdfVersion, + excludeAnnotations, + saveForPrinting, + includeComments, + outputFormat, + optimize, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PdfFormOption { + /// The value of the option. + var value: String + /// The label of the option. + var label: String + + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PdfFormOption? { + let value = pigeonVar_list[0] as! String + let label = pigeonVar_list[1] as! String + + return PdfFormOption( + value: value, + label: label + ) + } + func toList() -> [Any?] { + return [ + value, + label, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct FormFieldData { + var name: String + var alternativeFieldName: String? = nil + var fullyQualifiedName: String? = nil + var type: PdfFormFieldTypes + var annotations: Any? = nil + var isReadOnly: Bool? = nil + var isRequired: Bool? = nil + var isExported: Bool? = nil + var isDirty: Bool? = nil + var options: [PdfFormOption?]? = nil + + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> FormFieldData? { + let name = pigeonVar_list[0] as! String + let alternativeFieldName: String? = nilOrValue(pigeonVar_list[1]) + let fullyQualifiedName: String? = nilOrValue(pigeonVar_list[2]) + let type = pigeonVar_list[3] as! PdfFormFieldTypes + let annotations: Any? = pigeonVar_list[4] + let isReadOnly: Bool? = nilOrValue(pigeonVar_list[5]) + let isRequired: Bool? = nilOrValue(pigeonVar_list[6]) + let isExported: Bool? = nilOrValue(pigeonVar_list[7]) + let isDirty: Bool? = nilOrValue(pigeonVar_list[8]) + let options: [PdfFormOption?]? = nilOrValue(pigeonVar_list[9]) + + return FormFieldData( + name: name, + alternativeFieldName: alternativeFieldName, + fullyQualifiedName: fullyQualifiedName, + type: type, + annotations: annotations, + isReadOnly: isReadOnly, + isRequired: isRequired, + isExported: isExported, + isDirty: isDirty, + options: options + ) + } + func toList() -> [Any?] { + return [ + name, + alternativeFieldName, + fullyQualifiedName, + type, + annotations, + isReadOnly, + isRequired, + isExported, + isDirty, + options, + ] + } +} + +private class PspdfkitApiPigeonCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 129: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return AndroidPermissionStatus(rawValue: enumResultAsInt) + } + return nil + case 130: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return AnnotationType(rawValue: enumResultAsInt) + } + return nil + case 131: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return AnnotationTool(rawValue: enumResultAsInt) + } + return nil + case 132: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return AnnotationToolVariant(rawValue: enumResultAsInt) + } + return nil + case 133: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return AnnotationProcessingMode(rawValue: enumResultAsInt) + } + return nil + case 134: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return DocumentPermissions(rawValue: enumResultAsInt) + } + return nil + case 135: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return PdfVersion(rawValue: enumResultAsInt) + } + return nil + case 136: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return PdfFormFieldTypes(rawValue: enumResultAsInt) + } + return nil + case 137: + return PdfRect.fromList(self.readValue() as! [Any?]) + case 138: + return PageInfo.fromList(self.readValue() as! [Any?]) + case 139: + return DocumentSaveOptions.fromList(self.readValue() as! [Any?]) + case 140: + return PdfFormOption.fromList(self.readValue() as! [Any?]) + case 141: + return FormFieldData.fromList(self.readValue() as! [Any?]) + default: + return super.readValue(ofType: type) + } + } +} + +private class PspdfkitApiPigeonCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? AndroidPermissionStatus { + super.writeByte(129) + super.writeValue(value.rawValue) + } else if let value = value as? AnnotationType { + super.writeByte(130) + super.writeValue(value.rawValue) + } else if let value = value as? AnnotationTool { + super.writeByte(131) + super.writeValue(value.rawValue) + } else if let value = value as? AnnotationToolVariant { + super.writeByte(132) + super.writeValue(value.rawValue) + } else if let value = value as? AnnotationProcessingMode { + super.writeByte(133) + super.writeValue(value.rawValue) + } else if let value = value as? DocumentPermissions { + super.writeByte(134) + super.writeValue(value.rawValue) + } else if let value = value as? PdfVersion { + super.writeByte(135) + super.writeValue(value.rawValue) + } else if let value = value as? PdfFormFieldTypes { + super.writeByte(136) + super.writeValue(value.rawValue) + } else if let value = value as? PdfRect { + super.writeByte(137) + super.writeValue(value.toList()) + } else if let value = value as? PageInfo { + super.writeByte(138) + super.writeValue(value.toList()) + } else if let value = value as? DocumentSaveOptions { + super.writeByte(139) + super.writeValue(value.toList()) + } else if let value = value as? PdfFormOption { + super.writeByte(140) + super.writeValue(value.toList()) + } else if let value = value as? FormFieldData { + super.writeByte(141) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class PspdfkitApiPigeonCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + return PspdfkitApiPigeonCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + return PspdfkitApiPigeonCodecWriter(data: data) + } +} + +class PspdfkitApiPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { + static let shared = PspdfkitApiPigeonCodec(readerWriter: PspdfkitApiPigeonCodecReaderWriter()) +} + + +/// The API for interacting with a PDF document. +/// +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol PspdfkitApi { + func getFrameworkVersion(completion: @escaping (Result) -> Void) + func setLicenseKey(licenseKey: String?, completion: @escaping (Result) -> Void) + func setLicenseKeys(androidLicenseKey: String?, iOSLicenseKey: String?, webLicenseKey: String?, completion: @escaping (Result) -> Void) + func present(document: String, configuration: [String: Any]?, completion: @escaping (Result) -> Void) + func presentInstant(serverUrl: String, jwt: String, configuration: [String: Any]?, completion: @escaping (Result) -> Void) + func setFormFieldValue(value: String, fullyQualifiedName: String, completion: @escaping (Result) -> Void) + func getFormFieldValue(fullyQualifiedName: String, completion: @escaping (Result) -> Void) + func applyInstantJson(annotationsJson: String, completion: @escaping (Result) -> Void) + func exportInstantJson(completion: @escaping (Result) -> Void) + func addAnnotation(jsonAnnotation: String, completion: @escaping (Result) -> Void) + func removeAnnotation(jsonAnnotation: String, completion: @escaping (Result) -> Void) + func getAnnotations(pageIndex: Int64, type: String, completion: @escaping (Result) -> Void) + func getAllUnsavedAnnotations(completion: @escaping (Result) -> Void) + func processAnnotations(type: AnnotationType, processingMode: AnnotationProcessingMode, destinationPath: String, completion: @escaping (Result) -> Void) + func importXfdf(xfdfString: String, completion: @escaping (Result) -> Void) + func exportXfdf(xfdfPath: String, completion: @escaping (Result) -> Void) + func save(completion: @escaping (Result) -> Void) + func setDelayForSyncingLocalChanges(delay: Double, completion: @escaping (Result) -> Void) + func setListenToServerChanges(listen: Bool, completion: @escaping (Result) -> Void) + func syncAnnotations(completion: @escaping (Result) -> Void) + func checkAndroidWriteExternalStoragePermission(completion: @escaping (Result) -> Void) + func requestAndroidWriteExternalStoragePermission(completion: @escaping (Result) -> Void) + func openAndroidSettings(completion: @escaping (Result) -> Void) + func setAnnotationPresetConfigurations(configurations: [String: Any?], completion: @escaping (Result) -> Void) + func getTemporaryDirectory(completion: @escaping (Result) -> Void) + func getAuthorName(completion: @escaping (Result) -> Void) + /// Generate PDF from Images, Template, and Patterns. + /// [pages]: [NewPage]s to be added to the PDF. + /// [outputPath]: The path to the output file. + /// Returns the path to the generated PDF path or null if the input is invalid or if the PDF generation fails. + func generatePdf(pages: [[String: Any]], outputPath: String, completion: @escaping (Result) -> Void) + /// Generates a PDF from HTML string. + /// + /// [html]: The HTML string to be converted to PDF. + /// [outPutFile]: The path to the output file. + /// Returns the path to the generated PDF file or null if the input is invalid or if the PDF generation fails. + func generatePdfFromHtmlString(html: String, outPutFile: String, options: [String: Any]?, completion: @escaping (Result) -> Void) + func generatePdfFromHtmlUri(htmlUri: String, outPutFile: String, options: [String: Any]?, completion: @escaping (Result) -> Void) +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class PspdfkitApiSetup { + static var codec: FlutterStandardMessageCodec { PspdfkitApiPigeonCodec.shared } + /// Sets up an instance of `PspdfkitApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: PspdfkitApi?, messageChannelSuffix: String = "") { + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + let getFrameworkVersionChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getFrameworkVersion\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getFrameworkVersionChannel.setMessageHandler { _, reply in + api.getFrameworkVersion { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getFrameworkVersionChannel.setMessageHandler(nil) + } + let setLicenseKeyChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setLicenseKey\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setLicenseKeyChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let licenseKeyArg: String? = nilOrValue(args[0]) + api.setLicenseKey(licenseKey: licenseKeyArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setLicenseKeyChannel.setMessageHandler(nil) + } + let setLicenseKeysChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setLicenseKeys\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setLicenseKeysChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let androidLicenseKeyArg: String? = nilOrValue(args[0]) + let iOSLicenseKeyArg: String? = nilOrValue(args[1]) + let webLicenseKeyArg: String? = nilOrValue(args[2]) + api.setLicenseKeys(androidLicenseKey: androidLicenseKeyArg, iOSLicenseKey: iOSLicenseKeyArg, webLicenseKey: webLicenseKeyArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setLicenseKeysChannel.setMessageHandler(nil) + } + let presentChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.present\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + presentChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let documentArg = args[0] as! String + let configurationArg: [String: Any]? = nilOrValue(args[1]) + api.present(document: documentArg, configuration: configurationArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + presentChannel.setMessageHandler(nil) + } + let presentInstantChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.presentInstant\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + presentInstantChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let serverUrlArg = args[0] as! String + let jwtArg = args[1] as! String + let configurationArg: [String: Any]? = nilOrValue(args[2]) + api.presentInstant(serverUrl: serverUrlArg, jwt: jwtArg, configuration: configurationArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + presentInstantChannel.setMessageHandler(nil) + } + let setFormFieldValueChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setFormFieldValue\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setFormFieldValueChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let valueArg = args[0] as! String + let fullyQualifiedNameArg = args[1] as! String + api.setFormFieldValue(value: valueArg, fullyQualifiedName: fullyQualifiedNameArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setFormFieldValueChannel.setMessageHandler(nil) + } + let getFormFieldValueChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getFormFieldValue\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getFormFieldValueChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let fullyQualifiedNameArg = args[0] as! String + api.getFormFieldValue(fullyQualifiedName: fullyQualifiedNameArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getFormFieldValueChannel.setMessageHandler(nil) + } + let applyInstantJsonChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.applyInstantJson\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + applyInstantJsonChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let annotationsJsonArg = args[0] as! String + api.applyInstantJson(annotationsJson: annotationsJsonArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + applyInstantJsonChannel.setMessageHandler(nil) + } + let exportInstantJsonChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.exportInstantJson\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + exportInstantJsonChannel.setMessageHandler { _, reply in + api.exportInstantJson { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + exportInstantJsonChannel.setMessageHandler(nil) + } + let addAnnotationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.addAnnotation\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addAnnotationChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let jsonAnnotationArg = args[0] as! String + api.addAnnotation(jsonAnnotation: jsonAnnotationArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addAnnotationChannel.setMessageHandler(nil) + } + let removeAnnotationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.removeAnnotation\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + removeAnnotationChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let jsonAnnotationArg = args[0] as! String + api.removeAnnotation(jsonAnnotation: jsonAnnotationArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + removeAnnotationChannel.setMessageHandler(nil) + } + let getAnnotationsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getAnnotations\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAnnotationsChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let pageIndexArg = args[0] as! Int64 + let typeArg = args[1] as! String + api.getAnnotations(pageIndex: pageIndexArg, type: typeArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getAnnotationsChannel.setMessageHandler(nil) + } + let getAllUnsavedAnnotationsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getAllUnsavedAnnotations\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAllUnsavedAnnotationsChannel.setMessageHandler { _, reply in + api.getAllUnsavedAnnotations { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getAllUnsavedAnnotationsChannel.setMessageHandler(nil) + } + let processAnnotationsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.processAnnotations\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + processAnnotationsChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let typeArg = args[0] as! AnnotationType + let processingModeArg = args[1] as! AnnotationProcessingMode + let destinationPathArg = args[2] as! String + api.processAnnotations(type: typeArg, processingMode: processingModeArg, destinationPath: destinationPathArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + processAnnotationsChannel.setMessageHandler(nil) + } + let importXfdfChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.importXfdf\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + importXfdfChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let xfdfStringArg = args[0] as! String + api.importXfdf(xfdfString: xfdfStringArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + importXfdfChannel.setMessageHandler(nil) + } + let exportXfdfChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.exportXfdf\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + exportXfdfChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let xfdfPathArg = args[0] as! String + api.exportXfdf(xfdfPath: xfdfPathArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + exportXfdfChannel.setMessageHandler(nil) + } + let saveChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.save\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + saveChannel.setMessageHandler { _, reply in + api.save { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + saveChannel.setMessageHandler(nil) + } + let setDelayForSyncingLocalChangesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setDelayForSyncingLocalChanges\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setDelayForSyncingLocalChangesChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let delayArg = args[0] as! Double + api.setDelayForSyncingLocalChanges(delay: delayArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setDelayForSyncingLocalChangesChannel.setMessageHandler(nil) + } + let setListenToServerChangesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setListenToServerChanges\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setListenToServerChangesChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let listenArg = args[0] as! Bool + api.setListenToServerChanges(listen: listenArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setListenToServerChangesChannel.setMessageHandler(nil) + } + let syncAnnotationsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.syncAnnotations\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + syncAnnotationsChannel.setMessageHandler { _, reply in + api.syncAnnotations { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + syncAnnotationsChannel.setMessageHandler(nil) + } + let checkAndroidWriteExternalStoragePermissionChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.checkAndroidWriteExternalStoragePermission\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + checkAndroidWriteExternalStoragePermissionChannel.setMessageHandler { _, reply in + api.checkAndroidWriteExternalStoragePermission { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + checkAndroidWriteExternalStoragePermissionChannel.setMessageHandler(nil) + } + let requestAndroidWriteExternalStoragePermissionChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.requestAndroidWriteExternalStoragePermission\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + requestAndroidWriteExternalStoragePermissionChannel.setMessageHandler { _, reply in + api.requestAndroidWriteExternalStoragePermission { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + requestAndroidWriteExternalStoragePermissionChannel.setMessageHandler(nil) + } + let openAndroidSettingsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.openAndroidSettings\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + openAndroidSettingsChannel.setMessageHandler { _, reply in + api.openAndroidSettings { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + openAndroidSettingsChannel.setMessageHandler(nil) + } + let setAnnotationPresetConfigurationsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setAnnotationPresetConfigurations\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setAnnotationPresetConfigurationsChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let configurationsArg = args[0] as! [String: Any?] + api.setAnnotationPresetConfigurations(configurations: configurationsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setAnnotationPresetConfigurationsChannel.setMessageHandler(nil) + } + let getTemporaryDirectoryChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getTemporaryDirectory\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getTemporaryDirectoryChannel.setMessageHandler { _, reply in + api.getTemporaryDirectory { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getTemporaryDirectoryChannel.setMessageHandler(nil) + } + let getAuthorNameChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getAuthorName\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAuthorNameChannel.setMessageHandler { _, reply in + api.getAuthorName { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getAuthorNameChannel.setMessageHandler(nil) + } + /// Generate PDF from Images, Template, and Patterns. + /// [pages]: [NewPage]s to be added to the PDF. + /// [outputPath]: The path to the output file. + /// Returns the path to the generated PDF path or null if the input is invalid or if the PDF generation fails. + let generatePdfChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.generatePdf\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + generatePdfChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let pagesArg = args[0] as! [[String: Any]] + let outputPathArg = args[1] as! String + api.generatePdf(pages: pagesArg, outputPath: outputPathArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + generatePdfChannel.setMessageHandler(nil) + } + /// Generates a PDF from HTML string. + /// + /// [html]: The HTML string to be converted to PDF. + /// [outPutFile]: The path to the output file. + /// Returns the path to the generated PDF file or null if the input is invalid or if the PDF generation fails. + let generatePdfFromHtmlStringChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.generatePdfFromHtmlString\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + generatePdfFromHtmlStringChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let htmlArg = args[0] as! String + let outPutFileArg = args[1] as! String + let optionsArg: [String: Any]? = nilOrValue(args[2]) + api.generatePdfFromHtmlString(html: htmlArg, outPutFile: outPutFileArg, options: optionsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + generatePdfFromHtmlStringChannel.setMessageHandler(nil) + } + let generatePdfFromHtmlUriChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.generatePdfFromHtmlUri\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + generatePdfFromHtmlUriChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let htmlUriArg = args[0] as! String + let outPutFileArg = args[1] as! String + let optionsArg: [String: Any]? = nilOrValue(args[2]) + api.generatePdfFromHtmlUri(htmlUri: htmlUriArg, outPutFile: outPutFileArg, options: optionsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + generatePdfFromHtmlUriChannel.setMessageHandler(nil) + } + } +} +/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. +protocol PspdfkitFlutterApiCallbacksProtocol { + /// onPAuse callback for FlutterPdfActivity + func onPdfActivityOnPause(completion: @escaping (Result) -> Void) + func onPdfFragmentAdded(completion: @escaping (Result) -> Void) + func onDocumentLoaded(documentId documentIdArg: String, completion: @escaping (Result) -> Void) + /// ViewControllerWillDismiss callback for PDFViewController + func onPdfViewControllerWillDismiss(completion: @escaping (Result) -> Void) + /// ViewControllerDidDismiss callback for PDFViewController + func onPdfViewControllerDidDismiss(completion: @escaping (Result) -> Void) + /// Called when instant synchronization starts. + func onInstantSyncStarted(documentId documentIdArg: String, completion: @escaping (Result) -> Void) + /// Called when instant synchronization ends. + func onInstantSyncFinished(documentId documentIdArg: String, completion: @escaping (Result) -> Void) + /// Called when instant synchronization fails. + func onInstantSyncFailed(documentId documentIdArg: String, error errorArg: String, completion: @escaping (Result) -> Void) + /// Called when instant authentication is done. + func onInstantAuthenticationFinished(documentId documentIdArg: String, validJWT validJWTArg: String, completion: @escaping (Result) -> Void) + /// Called when instant authentication fails. + func onInstantAuthenticationFailed(documentId documentIdArg: String, error errorArg: String, completion: @escaping (Result) -> Void) + /// Only available on iOS. + /// Called when instant document download is done. + func onInstantDownloadFinished(documentId documentIdArg: String, completion: @escaping (Result) -> Void) + /// Only available on iOS. + /// Called when instant document download fails. + func onInstantDownloadFailed(documentId documentIdArg: String, error errorArg: String, completion: @escaping (Result) -> Void) +} +class PspdfkitFlutterApiCallbacks: PspdfkitFlutterApiCallbacksProtocol { + private let binaryMessenger: FlutterBinaryMessenger + private let messageChannelSuffix: String + init(binaryMessenger: FlutterBinaryMessenger, messageChannelSuffix: String = "") { + self.binaryMessenger = binaryMessenger + self.messageChannelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + } + var codec: PspdfkitApiPigeonCodec { + return PspdfkitApiPigeonCodec.shared + } + /// onPAuse callback for FlutterPdfActivity + func onPdfActivityOnPause(completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onPdfActivityOnPause\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + func onPdfFragmentAdded(completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onPdfFragmentAdded\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + func onDocumentLoaded(documentId documentIdArg: String, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onDocumentLoaded\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([documentIdArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + /// ViewControllerWillDismiss callback for PDFViewController + func onPdfViewControllerWillDismiss(completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onPdfViewControllerWillDismiss\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + /// ViewControllerDidDismiss callback for PDFViewController + func onPdfViewControllerDidDismiss(completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onPdfViewControllerDidDismiss\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + /// Called when instant synchronization starts. + func onInstantSyncStarted(documentId documentIdArg: String, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncStarted\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([documentIdArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + /// Called when instant synchronization ends. + func onInstantSyncFinished(documentId documentIdArg: String, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncFinished\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([documentIdArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + /// Called when instant synchronization fails. + func onInstantSyncFailed(documentId documentIdArg: String, error errorArg: String, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncFailed\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([documentIdArg, errorArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + /// Called when instant authentication is done. + func onInstantAuthenticationFinished(documentId documentIdArg: String, validJWT validJWTArg: String, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantAuthenticationFinished\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([documentIdArg, validJWTArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + /// Called when instant authentication fails. + func onInstantAuthenticationFailed(documentId documentIdArg: String, error errorArg: String, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantAuthenticationFailed\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([documentIdArg, errorArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + /// Only available on iOS. + /// Called when instant document download is done. + func onInstantDownloadFinished(documentId documentIdArg: String, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantDownloadFinished\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([documentIdArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + /// Only available on iOS. + /// Called when instant document download fails. + func onInstantDownloadFailed(documentId documentIdArg: String, error errorArg: String, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantDownloadFailed\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([documentIdArg, errorArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } +} +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol PspdfkitWidgetControllerApi { + /// Sets the value of a form field by specifying its fully qualified field name. + /// This method is deprecated. Use [PdfDocument.setFormFieldValue] instead. + func setFormFieldValue(value: String, fullyQualifiedName: String, completion: @escaping (Result) -> Void) + /// Gets the form field value by specifying its fully qualified name. + func getFormFieldValue(fullyQualifiedName: String, completion: @escaping (Result) -> Void) + /// Applies Instant document JSON to the presented document. + func applyInstantJson(annotationsJson: String, completion: @escaping (Result) -> Void) + /// Exports Instant document JSON from the presented document. + func exportInstantJson(completion: @escaping (Result) -> Void) + /// Adds the given annotation to the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + func addAnnotation(jsonAnnotation: String, completion: @escaping (Result) -> Void) + /// Removes the given annotation from the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + func removeAnnotation(jsonAnnotation: String, completion: @escaping (Result) -> Void) + /// Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. + func getAnnotations(pageIndex: Int64, type: String, completion: @escaping (Result) -> Void) + /// Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. + func getAllUnsavedAnnotations(completion: @escaping (Result) -> Void) + /// Processes annotations of the given type with the provided processing + /// mode and stores the PDF at the given destination path. + func processAnnotations(type: AnnotationType, processingMode: AnnotationProcessingMode, destinationPath: String, completion: @escaping (Result) -> Void) + /// Imports annotations from the XFDF file at the given path. + func importXfdf(xfdfString: String, completion: @escaping (Result) -> Void) + /// Exports annotations to the XFDF file at the given path. + func exportXfdf(xfdfPath: String, completion: @escaping (Result) -> Void) + /// Saves the document back to its original location if it has been changed. + /// If there were no changes to the document, the document file will not be modified. + func save(completion: @escaping (Result) -> Void) + /// Sets the annotation preset configurations for the given annotation tools. + /// @param configurations A map of annotation tools and their corresponding configurations. + /// @param modifyAssociatedAnnotations Whether to modify the annotations associated with the old configuration. Only used for Android. + /// @return True if the configurations were set successfully, false otherwise. + func setAnnotationConfigurations(configurations: [String: [String: Any]], completion: @escaping (Result) -> Void) + /// Gets the visible rect of the given page. + /// pageIndex The index of the page. This is a zero-based index. + /// Returns a [Future] that completes with the visible rect of the given page. + func getVisibleRect(pageIndex: Int64, completion: @escaping (Result) -> Void) + /// Zooms to the given rect on the given page. + /// pageIndex The index of the page. This is a zero-based index. + /// rect The rect to zoom to. + /// Returns a [Future] that completes when the zoom operation is done. + func zoomToRect(pageIndex: Int64, rect: PdfRect, animated: Bool?, duration: Double?, completion: @escaping (Result) -> Void) + /// Gets the zoom scale of the given page. + /// pageIndex The index of the page. This is a zero-based index. + /// Returns a [Future] that completes with the zoom scale of the given page. + func getZoomScale(pageIndex: Int64, completion: @escaping (Result) -> Void) +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class PspdfkitWidgetControllerApiSetup { + static var codec: FlutterStandardMessageCodec { PspdfkitApiPigeonCodec.shared } + /// Sets up an instance of `PspdfkitWidgetControllerApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: PspdfkitWidgetControllerApi?, messageChannelSuffix: String = "") { + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + /// Sets the value of a form field by specifying its fully qualified field name. + /// This method is deprecated. Use [PdfDocument.setFormFieldValue] instead. + let setFormFieldValueChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.setFormFieldValue\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setFormFieldValueChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let valueArg = args[0] as! String + let fullyQualifiedNameArg = args[1] as! String + api.setFormFieldValue(value: valueArg, fullyQualifiedName: fullyQualifiedNameArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setFormFieldValueChannel.setMessageHandler(nil) + } + /// Gets the form field value by specifying its fully qualified name. + let getFormFieldValueChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getFormFieldValue\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getFormFieldValueChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let fullyQualifiedNameArg = args[0] as! String + api.getFormFieldValue(fullyQualifiedName: fullyQualifiedNameArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getFormFieldValueChannel.setMessageHandler(nil) + } + /// Applies Instant document JSON to the presented document. + let applyInstantJsonChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.applyInstantJson\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + applyInstantJsonChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let annotationsJsonArg = args[0] as! String + api.applyInstantJson(annotationsJson: annotationsJsonArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + applyInstantJsonChannel.setMessageHandler(nil) + } + /// Exports Instant document JSON from the presented document. + let exportInstantJsonChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.exportInstantJson\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + exportInstantJsonChannel.setMessageHandler { _, reply in + api.exportInstantJson { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + exportInstantJsonChannel.setMessageHandler(nil) + } + /// Adds the given annotation to the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + let addAnnotationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.addAnnotation\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addAnnotationChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let jsonAnnotationArg = args[0] as! String + api.addAnnotation(jsonAnnotation: jsonAnnotationArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addAnnotationChannel.setMessageHandler(nil) + } + /// Removes the given annotation from the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + let removeAnnotationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.removeAnnotation\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + removeAnnotationChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let jsonAnnotationArg = args[0] as! String + api.removeAnnotation(jsonAnnotation: jsonAnnotationArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + removeAnnotationChannel.setMessageHandler(nil) + } + /// Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. + let getAnnotationsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getAnnotations\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAnnotationsChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let pageIndexArg = args[0] as! Int64 + let typeArg = args[1] as! String + api.getAnnotations(pageIndex: pageIndexArg, type: typeArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getAnnotationsChannel.setMessageHandler(nil) + } + /// Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. + let getAllUnsavedAnnotationsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getAllUnsavedAnnotations\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAllUnsavedAnnotationsChannel.setMessageHandler { _, reply in + api.getAllUnsavedAnnotations { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getAllUnsavedAnnotationsChannel.setMessageHandler(nil) + } + /// Processes annotations of the given type with the provided processing + /// mode and stores the PDF at the given destination path. + let processAnnotationsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.processAnnotations\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + processAnnotationsChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let typeArg = args[0] as! AnnotationType + let processingModeArg = args[1] as! AnnotationProcessingMode + let destinationPathArg = args[2] as! String + api.processAnnotations(type: typeArg, processingMode: processingModeArg, destinationPath: destinationPathArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + processAnnotationsChannel.setMessageHandler(nil) + } + /// Imports annotations from the XFDF file at the given path. + let importXfdfChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.importXfdf\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + importXfdfChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let xfdfStringArg = args[0] as! String + api.importXfdf(xfdfString: xfdfStringArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + importXfdfChannel.setMessageHandler(nil) + } + /// Exports annotations to the XFDF file at the given path. + let exportXfdfChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.exportXfdf\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + exportXfdfChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let xfdfPathArg = args[0] as! String + api.exportXfdf(xfdfPath: xfdfPathArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + exportXfdfChannel.setMessageHandler(nil) + } + /// Saves the document back to its original location if it has been changed. + /// If there were no changes to the document, the document file will not be modified. + let saveChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.save\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + saveChannel.setMessageHandler { _, reply in + api.save { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + saveChannel.setMessageHandler(nil) + } + /// Sets the annotation preset configurations for the given annotation tools. + /// @param configurations A map of annotation tools and their corresponding configurations. + /// @param modifyAssociatedAnnotations Whether to modify the annotations associated with the old configuration. Only used for Android. + /// @return True if the configurations were set successfully, false otherwise. + let setAnnotationConfigurationsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.setAnnotationConfigurations\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setAnnotationConfigurationsChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let configurationsArg = args[0] as! [String: [String: Any]] + api.setAnnotationConfigurations(configurations: configurationsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setAnnotationConfigurationsChannel.setMessageHandler(nil) + } + /// Gets the visible rect of the given page. + /// pageIndex The index of the page. This is a zero-based index. + /// Returns a [Future] that completes with the visible rect of the given page. + let getVisibleRectChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getVisibleRect\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getVisibleRectChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let pageIndexArg = args[0] as! Int64 + api.getVisibleRect(pageIndex: pageIndexArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getVisibleRectChannel.setMessageHandler(nil) + } + /// Zooms to the given rect on the given page. + /// pageIndex The index of the page. This is a zero-based index. + /// rect The rect to zoom to. + /// Returns a [Future] that completes when the zoom operation is done. + let zoomToRectChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.zoomToRect\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + zoomToRectChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let pageIndexArg = args[0] as! Int64 + let rectArg = args[1] as! PdfRect + let animatedArg: Bool? = nilOrValue(args[2]) + let durationArg: Double? = nilOrValue(args[3]) + api.zoomToRect(pageIndex: pageIndexArg, rect: rectArg, animated: animatedArg, duration: durationArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + zoomToRectChannel.setMessageHandler(nil) + } + /// Gets the zoom scale of the given page. + /// pageIndex The index of the page. This is a zero-based index. + /// Returns a [Future] that completes with the zoom scale of the given page. + let getZoomScaleChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getZoomScale\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getZoomScaleChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let pageIndexArg = args[0] as! Int64 + api.getZoomScale(pageIndex: pageIndexArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getZoomScaleChannel.setMessageHandler(nil) + } + } +} +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol PdfDocumentApi { + /// Returns the page info for the given page index. + /// pageIndex The index of the page. This is a zero-based index. + func getPageInfo(pageIndex: Int64, completion: @escaping (Result) -> Void) + /// Exports the document as a PDF. + /// options:[DocumentSaveOptions] The options to use when exporting the document. + /// Returns a [Uint8List] containing the exported PDF data. + func exportPdf(options: DocumentSaveOptions?, completion: @escaping (Result) -> Void) + func getFormField(fieldName: String, completion: @escaping (Result<[String: Any?], Error>) -> Void) + /// Returns a list of all form fields in the document. + func getFormFields(completion: @escaping (Result<[[String: Any?]], Error>) -> Void) + /// Sets the value of a form field by specifying its fully qualified field name. + func setFormFieldValue(value: String, fullyQualifiedName: String, completion: @escaping (Result) -> Void) + /// Gets the form field value by specifying its fully qualified name. + func getFormFieldValue(fullyQualifiedName: String, completion: @escaping (Result) -> Void) + /// Applies Instant document JSON to the presented document. + func applyInstantJson(annotationsJson: String, completion: @escaping (Result) -> Void) + /// Exports Instant document JSON from the presented document. + func exportInstantJson(completion: @escaping (Result) -> Void) + /// Adds the given annotation to the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + func addAnnotation(jsonAnnotation: String, completion: @escaping (Result) -> Void) + /// Removes the given annotation from the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + func removeAnnotation(jsonAnnotation: String, completion: @escaping (Result) -> Void) + /// Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. + func getAnnotations(pageIndex: Int64, type: String, completion: @escaping (Result) -> Void) + /// Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. + func getAllUnsavedAnnotations(completion: @escaping (Result) -> Void) + /// Imports annotations from the XFDF file at the given path. + func importXfdf(xfdfString: String, completion: @escaping (Result) -> Void) + /// Exports annotations to the XFDF file at the given path. + func exportXfdf(xfdfPath: String, completion: @escaping (Result) -> Void) + /// Saves the document back to its original location if it has been changed. + /// If there were no changes to the document, the document file will not be modified. + func save(outputPath: String?, options: DocumentSaveOptions?, completion: @escaping (Result) -> Void) +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class PdfDocumentApiSetup { + static var codec: FlutterStandardMessageCodec { PspdfkitApiPigeonCodec.shared } + /// Sets up an instance of `PdfDocumentApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: PdfDocumentApi?, messageChannelSuffix: String = "") { + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + /// Returns the page info for the given page index. + /// pageIndex The index of the page. This is a zero-based index. + let getPageInfoChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getPageInfo\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getPageInfoChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let pageIndexArg = args[0] as! Int64 + api.getPageInfo(pageIndex: pageIndexArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getPageInfoChannel.setMessageHandler(nil) + } + /// Exports the document as a PDF. + /// options:[DocumentSaveOptions] The options to use when exporting the document. + /// Returns a [Uint8List] containing the exported PDF data. + let exportPdfChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.exportPdf\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + exportPdfChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let optionsArg: DocumentSaveOptions? = nilOrValue(args[0]) + api.exportPdf(options: optionsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + exportPdfChannel.setMessageHandler(nil) + } + let getFormFieldChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getFormField\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getFormFieldChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let fieldNameArg = args[0] as! String + api.getFormField(fieldName: fieldNameArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getFormFieldChannel.setMessageHandler(nil) + } + /// Returns a list of all form fields in the document. + let getFormFieldsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getFormFields\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getFormFieldsChannel.setMessageHandler { _, reply in + api.getFormFields { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getFormFieldsChannel.setMessageHandler(nil) + } + /// Sets the value of a form field by specifying its fully qualified field name. + let setFormFieldValueChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.setFormFieldValue\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setFormFieldValueChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let valueArg = args[0] as! String + let fullyQualifiedNameArg = args[1] as! String + api.setFormFieldValue(value: valueArg, fullyQualifiedName: fullyQualifiedNameArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setFormFieldValueChannel.setMessageHandler(nil) + } + /// Gets the form field value by specifying its fully qualified name. + let getFormFieldValueChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getFormFieldValue\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getFormFieldValueChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let fullyQualifiedNameArg = args[0] as! String + api.getFormFieldValue(fullyQualifiedName: fullyQualifiedNameArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getFormFieldValueChannel.setMessageHandler(nil) + } + /// Applies Instant document JSON to the presented document. + let applyInstantJsonChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.applyInstantJson\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + applyInstantJsonChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let annotationsJsonArg = args[0] as! String + api.applyInstantJson(annotationsJson: annotationsJsonArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + applyInstantJsonChannel.setMessageHandler(nil) + } + /// Exports Instant document JSON from the presented document. + let exportInstantJsonChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.exportInstantJson\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + exportInstantJsonChannel.setMessageHandler { _, reply in + api.exportInstantJson { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + exportInstantJsonChannel.setMessageHandler(nil) + } + /// Adds the given annotation to the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + let addAnnotationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.addAnnotation\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addAnnotationChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let jsonAnnotationArg = args[0] as! String + api.addAnnotation(jsonAnnotation: jsonAnnotationArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addAnnotationChannel.setMessageHandler(nil) + } + /// Removes the given annotation from the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + let removeAnnotationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.removeAnnotation\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + removeAnnotationChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let jsonAnnotationArg = args[0] as! String + api.removeAnnotation(jsonAnnotation: jsonAnnotationArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + removeAnnotationChannel.setMessageHandler(nil) + } + /// Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. + let getAnnotationsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getAnnotations\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAnnotationsChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let pageIndexArg = args[0] as! Int64 + let typeArg = args[1] as! String + api.getAnnotations(pageIndex: pageIndexArg, type: typeArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getAnnotationsChannel.setMessageHandler(nil) + } + /// Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. + let getAllUnsavedAnnotationsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getAllUnsavedAnnotations\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAllUnsavedAnnotationsChannel.setMessageHandler { _, reply in + api.getAllUnsavedAnnotations { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getAllUnsavedAnnotationsChannel.setMessageHandler(nil) + } + /// Imports annotations from the XFDF file at the given path. + let importXfdfChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.importXfdf\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + importXfdfChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let xfdfStringArg = args[0] as! String + api.importXfdf(xfdfString: xfdfStringArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + importXfdfChannel.setMessageHandler(nil) + } + /// Exports annotations to the XFDF file at the given path. + let exportXfdfChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.exportXfdf\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + exportXfdfChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let xfdfPathArg = args[0] as! String + api.exportXfdf(xfdfPath: xfdfPathArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + exportXfdfChannel.setMessageHandler(nil) + } + /// Saves the document back to its original location if it has been changed. + /// If there were no changes to the document, the document file will not be modified. + let saveChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.save\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + saveChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let outputPathArg: String? = nilOrValue(args[0]) + let optionsArg: DocumentSaveOptions? = nilOrValue(args[1]) + api.save(outputPath: outputPathArg, options: optionsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + saveChannel.setMessageHandler(nil) + } + } +} +/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. +protocol PspdfkitWidgetCallbacksProtocol { + func onDocumentLoaded(documentId documentIdArg: String, completion: @escaping (Result) -> Void) + func onDocumentError(documentId documentIdArg: String, error errorArg: String, completion: @escaping (Result) -> Void) + func onPageChanged(documentId documentIdArg: String, pageIndex pageIndexArg: Int64, completion: @escaping (Result) -> Void) +} +class PspdfkitWidgetCallbacks: PspdfkitWidgetCallbacksProtocol { + private let binaryMessenger: FlutterBinaryMessenger + private let messageChannelSuffix: String + init(binaryMessenger: FlutterBinaryMessenger, messageChannelSuffix: String = "") { + self.binaryMessenger = binaryMessenger + self.messageChannelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + } + var codec: PspdfkitApiPigeonCodec { + return PspdfkitApiPigeonCodec.shared + } + func onDocumentLoaded(documentId documentIdArg: String, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onDocumentLoaded\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([documentIdArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + func onDocumentError(documentId documentIdArg: String, error errorArg: String, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onDocumentError\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([documentIdArg, errorArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + func onPageChanged(documentId documentIdArg: String, pageIndex pageIndexArg: Int64, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onPageChanged\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([documentIdArg, pageIndexArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PspdfkitApiError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } +} diff --git a/ios/Classes/helpers/FormHelper.swift b/ios/Classes/helpers/FormHelper.swift index 147b1d72..98700851 100644 --- a/ios/Classes/helpers/FormHelper.swift +++ b/ios/Classes/helpers/FormHelper.swift @@ -22,8 +22,8 @@ public class FormHelper: NSObject { "isReadOnly": formElement.isReadOnly, "fullyQualifiedName": formElement.formField?.fullyQualifiedName ?? "", "alternateFieldName": formElement.formField?.alternateFieldName ?? "", - "isNoExport": formElement.formField?.isNoExport, - "isDirty": formElement.formField?.dirty, + "isNoExport": formElement.formField?.isNoExport ?? false, + "isDirty": formElement.formField?.dirty ?? false, ] if(formElement.formField?.type == nil){ @@ -53,4 +53,55 @@ public class FormHelper: NSObject { return results } + + @objc public static func convertToFormFieldData(formFields: Array) -> NSArray { + + let results: [FormFieldData] = formFields.compactMap { (formElement) -> FormFieldData? in + + if(formElement.formField?.type == nil){ + return nil + } + + var type: PdfFormFieldTypes? = nil + + switch formElement.formField!.type { + case .pushButton: + type = PdfFormFieldTypes.button + case .checkBox: + type = PdfFormFieldTypes.checkbox + case .signature: + type = PdfFormFieldTypes.signature + case .text: + type = PdfFormFieldTypes.text + case .listBox: + type = PdfFormFieldTypes.listBox + case .comboBox: + type = PdfFormFieldTypes.comboBox + case .radioButton: + type = PdfFormFieldTypes.radioButton + case .unknown: + type = PdfFormFieldTypes.unknown + } + + guard let validType = type else { + return nil + } + + let formFieldData = FormFieldData( + name: formElement.name ?? "", + alternativeFieldName: formElement.formField?.alternateFieldName ?? "", + fullyQualifiedName: formElement.formField?.fullyQualifiedName ?? "", + type: validType, + annotations: formElement.formField?.annotations ?? [], + isReadOnly: formElement.isReadOnly, + isRequired: formElement.isRequired, + isExported: !(formElement.formField?.isNoExport ?? false), + isDirty: formElement.formField?.dirty ?? false + ) + + return formFieldData + } + return results as NSArray + } + } diff --git a/ios/pspdfkit_flutter.podspec b/ios/pspdfkit_flutter.podspec index 2200aa7e..ab5f0462 100644 --- a/ios/pspdfkit_flutter.podspec +++ b/ios/pspdfkit_flutter.podspec @@ -5,7 +5,7 @@ # Pod::Spec.new do |s| s.name = "pspdfkit_flutter" - s.version = "3.12.1" + s.version = "4.0.0" s.homepage = "https://PSPDFKit.com" s.documentation_url = "https://pspdfkit.com/guides/flutter" s.license = { type: "Commercial", file: "../LICENSE" } @@ -18,10 +18,10 @@ Pod::Spec.new do |s| s.source_files = "Classes/**/*.{h,m,swift}" s.public_header_files = "Classes/**/*.h" s.dependency("Flutter") - s.dependency("PSPDFKit", "13.9.1") - s.dependency("Instant", "13.9.1") + s.dependency("PSPDFKit", "14.1.1") + s.dependency("Instant", "14.1.1") s.swift_version = "5.0" s.platform = :ios, "15.0" - s.version = "3.12.1" + s.version = "4.0.0" s.pod_target_xcconfig = { "DEFINES_MODULE" => "YES", "SWIFT_INSTALL_OBJC_HEADER" => "NO" } end diff --git a/lib/pspdfkit.dart b/lib/pspdfkit.dart index 728975d5..271a310d 100644 --- a/lib/pspdfkit.dart +++ b/lib/pspdfkit.dart @@ -6,7 +6,6 @@ /// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. /// This notice may not be removed from this file. /// -library pspdfkit; import 'dart:async'; import 'package:flutter/foundation.dart'; @@ -28,33 +27,39 @@ export 'src/widgets/pspdfkit_widget_controller.dart'; export 'src/measurements/measurements.dart'; export 'src/processor/processor.dart'; export 'src/document/pdf_document.dart'; -export 'src/document/document_save_options.dart'; -export 'src/document/document_permissions.dart'; -export 'src/document/pdf_version.dart'; export 'src/forms/forms.dart'; -export 'src/processor/annotation_processing_mode.dart'; -export 'src/annotations/annotation_types.dart'; +export 'src/api/pspdfkit_api.g.dart'; -part 'src/android_permission_status.dart'; - -part 'src/pspdfkit_processor.dart'; - -part 'src/annotation_preset_configurations.dart'; - -part 'src/annotations/annotation_tools.dart'; +export 'src/pspdfkit_processor.dart'; +export 'src/annotation_preset_configurations.dart'; /// PSPDFKit plugin to load PDF and image documents on both platform iOS and Android. class Pspdfkit { + static bool useLegacy = false; + /// Gets the PSPDFKit framework version. static Future get frameworkVersion => PspdfkitFlutterPlatform.instance.getFrameworkVersion(); + static Future initialize({ + String? androidLicenseKey, + String? iosLicenseKey, + String? webLicenseKey, + bool? useLegacy, + }) async { + Pspdfkit.useLegacy = useLegacy ?? false; + await PspdfkitFlutterPlatform.instance + .setLicenseKeys(androidLicenseKey, iosLicenseKey, webLicenseKey); + } + /// Sets the license key. /// @param licenseKey The license key to be used. + @Deprecated('Use [Pspdfkit.initialize] instead.') static Future setLicenseKey(String? licenseKey) => PspdfkitFlutterPlatform.instance.setLicenseKey(licenseKey); /// Sets the license keys for both platforms. + @Deprecated('Use [Pspdfkit.initialize] instead.') static Future setLicenseKeys(String? androidLicenseKey, String? iOSLicenseKey, String? webLicenseKey) async => PspdfkitFlutterPlatform.instance @@ -171,6 +176,20 @@ class Pspdfkit { PspdfkitFlutterPlatform.instance .setAnnotationPresetConfigurations(configurations); + static Future generatePdfFromHtmlString( + String html, String outPutFile, [dynamic options]) async => + PspdfkitFlutterPlatform.instance + .generatePdfFromHtmlString(html, outPutFile); + + static Future generatePdfFromHtmlUri(Uri htmlUri, String outPutFile, + [dynamic options]) async => + PspdfkitFlutterPlatform.instance + .generatePdfFromHtmlUri(htmlUri, outPutFile); + + static Future generatePdf(List pages, String outPutFile, + [dynamic options]) async => + PspdfkitFlutterPlatform.instance.generatePdf(pages, outPutFile); + /// Get the annotation author name. static String authorName = PspdfkitFlutterPlatform.instance.authorName; diff --git a/lib/widgets/pspdfkit_widget_controller.dart b/lib/pspdfkit_flutter.dart similarity index 64% rename from lib/widgets/pspdfkit_widget_controller.dart rename to lib/pspdfkit_flutter.dart index 94617746..c7278d2d 100644 --- a/lib/widgets/pspdfkit_widget_controller.dart +++ b/lib/pspdfkit_flutter.dart @@ -1,5 +1,5 @@ /// -/// Copyright © 2018-2023 PSPDFKit GmbH. All rights reserved. +/// Copyright © 2018-2024 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. @@ -7,5 +7,5 @@ /// This notice may not be removed from this file. /// -@Deprecated('Use `package:pspdfkit_flutter/pspdfkit.dart` instead') -export '../src/widgets/pspdfkit_widget_controller.dart'; +/// pub.dev recommends using this file as the plugin entry point. In future, all exports will be moved here. +export 'pspdfkit.dart'; diff --git a/lib/src/annotation_preset_configurations.dart b/lib/src/annotation_preset_configurations.dart index 37305295..32c5dfa3 100644 --- a/lib/src/annotation_preset_configurations.dart +++ b/lib/src/annotation_preset_configurations.dart @@ -1,3 +1,5 @@ +import 'package:flutter/services.dart'; + /// /// Copyright © 2019-2024 PSPDFKit GmbH. All rights reserved. /// @@ -6,7 +8,6 @@ /// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. /// This notice may not be removed from this file. /// -part of pspdfkit; /// Annotation configuration class. Used to configure annotation presets. /// @@ -36,7 +37,7 @@ abstract class AnnotationConfiguration { /// Annotation configuration class for ink annotation. Ink annotations include: InkPen, MagicInk, Highlighter, Eraser and Signature. class InkAnnotationConfiguration extends AnnotationConfiguration { final Color? color; - final double thickness; + final double? thickness; final Color? fillColor; final double? alpha; final List? availableColors; @@ -71,7 +72,7 @@ class InkAnnotationConfiguration extends AnnotationConfiguration { map['color'] = color?.toHex(); } - if (thickness > 0.0) { + if (thickness != null && thickness! > 0.0) { map['thickness'] = thickness; } @@ -468,13 +469,13 @@ enum AnnotationConfigurationProperty { /// Line annotation start and end line ending style. lineEndingStyle, - /// Freetext annotation font name. + /// FreeText annotation font name. fontName, - /// Freetext annotation font size. + /// FreeText annotation font size. fontSize, - /// Freetext annotation text alignment. + /// FreeText annotation text alignment. textAlignment, /// Stamp annotation name. diff --git a/lib/src/annotations/annotation_tool_variant.dart b/lib/src/annotations/annotation_tool_variant.dart deleted file mode 100644 index 46e203df..00000000 --- a/lib/src/annotations/annotation_tool_variant.dart +++ /dev/null @@ -1,11 +0,0 @@ -enum AnnotationToolVariant { - inkPen, - inkMagic, - inkHighlighter, - freeText, - freeTextCallOut, - stamp, - image, - highlight, - underline, -} diff --git a/lib/src/annotations/annotation_tools.dart b/lib/src/annotations/annotation_tools.dart deleted file mode 100644 index 59a1bbcb..00000000 --- a/lib/src/annotations/annotation_tools.dart +++ /dev/null @@ -1,48 +0,0 @@ -/// -/// Copyright © 2019-2024 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. -/// -part of pspdfkit; - -/// Available annotation tools. -enum AnnotationTool { - inkPen, - inkMagic, - inkHighlighter, - freeText, - freeTextCallOut, - stamp, - image, - highlight, - underline, - squiggly, - strikeOut, - line, - arrow, - square, - circle, - polygon, - polyline, - eraser, - cloudy, - link, - caret, - richMedia, - screen, - file, - widget, - redaction, - signature, - stampImage, - note, - sound, - measurementAreaRect, - measurementAreaPolygon, - measurementAreaEllipse, - measurementPerimeter, - measurementDistance, -} diff --git a/lib/src/annotations/annotation_types.dart b/lib/src/annotations/annotation_types.dart deleted file mode 100644 index 6af2a366..00000000 --- a/lib/src/annotations/annotation_types.dart +++ /dev/null @@ -1,30 +0,0 @@ -enum AnnotationType { - all, - none, - undefined, - link, - highlight, - strikeout, - underline, - squiggly, - freeText, - ink, - square, - circle, - line, - note, - stamp, - caret, - richMedia, - screen, - widget, - file, - sound, - polygon, - polyline, - popup, - watermark, - trapNet, - type3d, - redact -} diff --git a/lib/src/api/pspdfkit_api.g.dart b/lib/src/api/pspdfkit_api.g.dart new file mode 100644 index 00000000..364b8657 --- /dev/null +++ b/lib/src/api/pspdfkit_api.g.dart @@ -0,0 +1,2478 @@ +// Copyright © 2024 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. +// Autogenerated from Pigeon (v22.5.0), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +PlatformException _createConnectionError(String channelName) { + return PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); +} + +List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { + if (empty) { + return []; + } + if (error == null) { + return [result]; + } + return [error.code, error.message, error.details]; +} + +enum AndroidPermissionStatus { + notDetermined, + denied, + authorized, + deniedNeverAsk, +} + +/// Represents the native annotation type. +enum AnnotationType { + all, + none, + undefined, + link, + highlight, + strikeout, + underline, + squiggly, + freeText, + ink, + square, + circle, + line, + note, + stamp, + caret, + richMedia, + screen, + widget, + file, + sound, + polygon, + polyline, + popup, + watermark, + trapNet, + type3d, + redact, +} + +enum AnnotationTool { + inkPen, + inkMagic, + inkHighlighter, + freeText, + freeTextCallOut, + stamp, + image, + highlight, + underline, + squiggly, + strikeOut, + line, + arrow, + square, + circle, + polygon, + polyline, + eraser, + cloudy, + link, + caret, + richMedia, + screen, + file, + widget, + redaction, + signature, + stampImage, + note, + sound, + measurementAreaRect, + measurementAreaPolygon, + measurementAreaEllipse, + measurementPerimeter, + measurementDistance, +} + +enum AnnotationToolVariant { + inkPen, + inkMagic, + inkHighlighter, + freeText, + freeTextCallOut, + stamp, + image, + highlight, + underline, +} + +enum AnnotationProcessingMode { + flatten, + remove, + embed, + print, +} + +enum DocumentPermissions { + /// Allow printing of document. + printing, + /// Modify the contents of the document. + modification, + /// Copy text and images from the document. + extract, + /// Add or modify text annotations, fill in interactive form fields. + annotationsAndForms, + /// Fill in existing interactive form fields (including signature fields). + fillForms, + /// Extract text and images from the document. + extractAccessibility, + /// Assemble the document (insert, rotate, or delete pages and create document outline items or thumbnail images). + assemble, + /// Print high quality. + printHighQuality, +} + +/// The PDF version of a document. +enum PdfVersion { + pdf_1_0, + pdf_1_1, + pdf_1_2, + pdf_1_3, + pdf_1_4, + pdf_1_5, + pdf_1_6, + pdf_1_7, +} + +enum PdfFormFieldTypes { + text, + checkbox, + radioButton, + comboBox, + listBox, + signature, + button, + unknown, +} + +class PdfRect { + PdfRect({ + required this.x, + required this.y, + required this.width, + required this.height, + }); + + double x; + + double y; + + double width; + + double height; + + Object encode() { + return [ + x, + y, + width, + height, + ]; + } + + static PdfRect decode(Object result) { + result as List; + return PdfRect( + x: result[0]! as double, + y: result[1]! as double, + width: result[2]! as double, + height: result[3]! as double, + ); + } +} + +class PageInfo { + PageInfo({ + required this.pageIndex, + required this.height, + required this.width, + required this.rotation, + this.label = '', + }); + + /// The index of the page. This is a zero-based index. + int pageIndex; + + /// The height of the page in points. + double height; + + /// The width of the page in points. + double width; + + /// The rotation of the page in degrees. + int rotation; + + /// The label of the page. + String label; + + Object encode() { + return [ + pageIndex, + height, + width, + rotation, + label, + ]; + } + + static PageInfo decode(Object result) { + result as List; + return PageInfo( + pageIndex: result[0]! as int, + height: result[1]! as double, + width: result[2]! as double, + rotation: result[3]! as int, + label: result[4]! as String, + ); + } +} + +class DocumentSaveOptions { + DocumentSaveOptions({ + this.userPassword, + this.ownerPassword, + this.flatten, + this.incremental, + this.permissions, + this.pdfVersion, + this.excludeAnnotations, + this.saveForPrinting, + this.includeComments, + this.outputFormat, + this.optimize, + }); + + /// The password is used to encrypt the document. On Web, it's used as the user password. + String? userPassword; + + /// The owner password is used to encrypt the document and set permissions. It's only used on Web. + String? ownerPassword; + + /// Flatten annotations and form fields into the page content. + bool? flatten; + + /// Whether to save the document incrementally. + bool? incremental; + + /// The permissions to set on the document. See [DocumentPermissions] for more information. + List? permissions; + + /// The PDF version to save the document as. + PdfVersion? pdfVersion; + + /// Whether to exclude annotations from the exported document. + bool? excludeAnnotations; + + /// Whether to exclude annotations that have the noPrint flag set to true from the exported document (Standalone only) + bool? saveForPrinting; + + /// Whether to include comments in the exported document (Server-Backed only). + bool? includeComments; + + /// Whether tp allow you to export a PDF in PDF/A format. + Object? outputFormat; + + /// Whether to optimize the document for the web. + bool? optimize; + + Object encode() { + return [ + userPassword, + ownerPassword, + flatten, + incremental, + permissions, + pdfVersion, + excludeAnnotations, + saveForPrinting, + includeComments, + outputFormat, + optimize, + ]; + } + + static DocumentSaveOptions decode(Object result) { + result as List; + return DocumentSaveOptions( + userPassword: result[0] as String?, + ownerPassword: result[1] as String?, + flatten: result[2] as bool?, + incremental: result[3] as bool?, + permissions: (result[4] as List?)?.cast(), + pdfVersion: result[5] as PdfVersion?, + excludeAnnotations: result[6] as bool?, + saveForPrinting: result[7] as bool?, + includeComments: result[8] as bool?, + outputFormat: result[9], + optimize: result[10] as bool?, + ); + } +} + +class PdfFormOption { + PdfFormOption({ + required this.value, + required this.label, + }); + + /// The value of the option. + String value; + + /// The label of the option. + String label; + + Object encode() { + return [ + value, + label, + ]; + } + + static PdfFormOption decode(Object result) { + result as List; + return PdfFormOption( + value: result[0]! as String, + label: result[1]! as String, + ); + } +} + +class FormFieldData { + FormFieldData({ + required this.name, + this.alternativeFieldName, + this.fullyQualifiedName, + required this.type, + this.annotations, + this.isReadOnly, + this.isRequired, + this.isExported, + this.isDirty, + this.options, + }); + + String name; + + String? alternativeFieldName; + + String? fullyQualifiedName; + + PdfFormFieldTypes type; + + Object? annotations; + + bool? isReadOnly; + + bool? isRequired; + + bool? isExported; + + bool? isDirty; + + List? options; + + Object encode() { + return [ + name, + alternativeFieldName, + fullyQualifiedName, + type, + annotations, + isReadOnly, + isRequired, + isExported, + isDirty, + options, + ]; + } + + static FormFieldData decode(Object result) { + result as List; + return FormFieldData( + name: result[0]! as String, + alternativeFieldName: result[1] as String?, + fullyQualifiedName: result[2] as String?, + type: result[3]! as PdfFormFieldTypes, + annotations: result[4], + isReadOnly: result[5] as bool?, + isRequired: result[6] as bool?, + isExported: result[7] as bool?, + isDirty: result[8] as bool?, + options: (result[9] as List?)?.cast(), + ); + } +} + + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is AndroidPermissionStatus) { + buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is AnnotationType) { + buffer.putUint8(130); + writeValue(buffer, value.index); + } else if (value is AnnotationTool) { + buffer.putUint8(131); + writeValue(buffer, value.index); + } else if (value is AnnotationToolVariant) { + buffer.putUint8(132); + writeValue(buffer, value.index); + } else if (value is AnnotationProcessingMode) { + buffer.putUint8(133); + writeValue(buffer, value.index); + } else if (value is DocumentPermissions) { + buffer.putUint8(134); + writeValue(buffer, value.index); + } else if (value is PdfVersion) { + buffer.putUint8(135); + writeValue(buffer, value.index); + } else if (value is PdfFormFieldTypes) { + buffer.putUint8(136); + writeValue(buffer, value.index); + } else if (value is PdfRect) { + buffer.putUint8(137); + writeValue(buffer, value.encode()); + } else if (value is PageInfo) { + buffer.putUint8(138); + writeValue(buffer, value.encode()); + } else if (value is DocumentSaveOptions) { + buffer.putUint8(139); + writeValue(buffer, value.encode()); + } else if (value is PdfFormOption) { + buffer.putUint8(140); + writeValue(buffer, value.encode()); + } else if (value is FormFieldData) { + buffer.putUint8(141); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + final int? value = readValue(buffer) as int?; + return value == null ? null : AndroidPermissionStatus.values[value]; + case 130: + final int? value = readValue(buffer) as int?; + return value == null ? null : AnnotationType.values[value]; + case 131: + final int? value = readValue(buffer) as int?; + return value == null ? null : AnnotationTool.values[value]; + case 132: + final int? value = readValue(buffer) as int?; + return value == null ? null : AnnotationToolVariant.values[value]; + case 133: + final int? value = readValue(buffer) as int?; + return value == null ? null : AnnotationProcessingMode.values[value]; + case 134: + final int? value = readValue(buffer) as int?; + return value == null ? null : DocumentPermissions.values[value]; + case 135: + final int? value = readValue(buffer) as int?; + return value == null ? null : PdfVersion.values[value]; + case 136: + final int? value = readValue(buffer) as int?; + return value == null ? null : PdfFormFieldTypes.values[value]; + case 137: + return PdfRect.decode(readValue(buffer)!); + case 138: + return PageInfo.decode(readValue(buffer)!); + case 139: + return DocumentSaveOptions.decode(readValue(buffer)!); + case 140: + return PdfFormOption.decode(readValue(buffer)!); + case 141: + return FormFieldData.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +/// The API for interacting with a PDF document. +class PspdfkitApi { + /// Constructor for [PspdfkitApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + PspdfkitApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future getFrameworkVersion() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getFrameworkVersion$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + Future setLicenseKey(String? licenseKey) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setLicenseKey$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([licenseKey]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future setLicenseKeys(String? androidLicenseKey, String? iOSLicenseKey, String? webLicenseKey) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setLicenseKeys$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([androidLicenseKey, iOSLicenseKey, webLicenseKey]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future present(String document, {Map? configuration}) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.present$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([document, configuration]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future presentInstant(String serverUrl, String jwt, {Map? configuration,}) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.presentInstant$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([serverUrl, jwt, configuration]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future setFormFieldValue(String value, String fullyQualifiedName) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setFormFieldValue$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([value, fullyQualifiedName]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future getFormFieldValue(String fullyQualifiedName) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getFormFieldValue$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([fullyQualifiedName]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + Future applyInstantJson(String annotationsJson) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.applyInstantJson$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([annotationsJson]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future exportInstantJson() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.exportInstantJson$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + Future addAnnotation(String jsonAnnotation) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.addAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([jsonAnnotation]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future removeAnnotation(String jsonAnnotation) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.removeAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([jsonAnnotation]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future getAnnotations(int pageIndex, String type) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([pageIndex, type]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return pigeonVar_replyList[0]; + } + } + + Future getAllUnsavedAnnotations() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getAllUnsavedAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return pigeonVar_replyList[0]; + } + } + + Future processAnnotations(AnnotationType type, AnnotationProcessingMode processingMode, String destinationPath) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.processAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([type, processingMode, destinationPath]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future importXfdf(String xfdfString) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.importXfdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([xfdfString]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future exportXfdf(String xfdfPath) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.exportXfdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([xfdfPath]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future save() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.save$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future setDelayForSyncingLocalChanges(double delay) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setDelayForSyncingLocalChanges$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([delay]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future setListenToServerChanges(bool listen) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setListenToServerChanges$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([listen]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future syncAnnotations() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.syncAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future checkAndroidWriteExternalStoragePermission() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.checkAndroidWriteExternalStoragePermission$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future requestAndroidWriteExternalStoragePermission() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.requestAndroidWriteExternalStoragePermission$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as AndroidPermissionStatus?)!; + } + } + + Future openAndroidSettings() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.openAndroidSettings$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future setAnnotationPresetConfigurations(Map configurations) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.setAnnotationPresetConfigurations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([configurations]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + Future getTemporaryDirectory() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getTemporaryDirectory$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as String?)!; + } + } + + Future getAuthorName() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.getAuthorName$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as String?)!; + } + } + + /// Generate PDF from Images, Template, and Patterns. + /// [pages]: [NewPage]s to be added to the PDF. + /// [outputPath]: The path to the output file. + /// Returns the path to the generated PDF path or null if the input is invalid or if the PDF generation fails. + Future generatePdf(List> pages, String outputPath) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.generatePdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([pages, outputPath]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + /// Generates a PDF from HTML string. + /// + /// [html]: The HTML string to be converted to PDF. + /// [outPutFile]: The path to the output file. + /// Returns the path to the generated PDF file or null if the input is invalid or if the PDF generation fails. + Future generatePdfFromHtmlString(String html, String outPutFile, Map? options) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.generatePdfFromHtmlString$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([html, outPutFile, options]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + Future generatePdfFromHtmlUri(String htmlUri, String outPutFile, Map? options) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitApi.generatePdfFromHtmlUri$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([htmlUri, outPutFile, options]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } +} + +abstract class PspdfkitFlutterApiCallbacks { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + /// onPAuse callback for FlutterPdfActivity + void onPdfActivityOnPause(); + + void onPdfFragmentAdded(); + + void onDocumentLoaded(String documentId); + + /// ViewControllerWillDismiss callback for PDFViewController + void onPdfViewControllerWillDismiss(); + + /// ViewControllerDidDismiss callback for PDFViewController + void onPdfViewControllerDidDismiss(); + + /// Called when instant synchronization starts. + void onInstantSyncStarted(String documentId); + + /// Called when instant synchronization ends. + void onInstantSyncFinished(String documentId); + + /// Called when instant synchronization fails. + void onInstantSyncFailed(String documentId, String error); + + /// Called when instant authentication is done. + void onInstantAuthenticationFinished(String documentId, String validJWT); + + /// Called when instant authentication fails. + void onInstantAuthenticationFailed(String documentId, String error); + + /// Only available on iOS. + /// Called when instant document download is done. + void onInstantDownloadFinished(String documentId); + + /// Only available on iOS. + /// Called when instant document download fails. + void onInstantDownloadFailed(String documentId, String error); + + static void setUp(PspdfkitFlutterApiCallbacks? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onPdfActivityOnPause$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + try { + api.onPdfActivityOnPause(); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onPdfFragmentAdded$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + try { + api.onPdfFragmentAdded(); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onDocumentLoaded$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onDocumentLoaded was null.'); + final List args = (message as List?)!; + final String? arg_documentId = (args[0] as String?); + assert(arg_documentId != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onDocumentLoaded was null, expected non-null String.'); + try { + api.onDocumentLoaded(arg_documentId!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onPdfViewControllerWillDismiss$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + try { + api.onPdfViewControllerWillDismiss(); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onPdfViewControllerDidDismiss$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + try { + api.onPdfViewControllerDidDismiss(); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncStarted$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncStarted was null.'); + final List args = (message as List?)!; + final String? arg_documentId = (args[0] as String?); + assert(arg_documentId != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncStarted was null, expected non-null String.'); + try { + api.onInstantSyncStarted(arg_documentId!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncFinished$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncFinished was null.'); + final List args = (message as List?)!; + final String? arg_documentId = (args[0] as String?); + assert(arg_documentId != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncFinished was null, expected non-null String.'); + try { + api.onInstantSyncFinished(arg_documentId!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncFailed$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncFailed was null.'); + final List args = (message as List?)!; + final String? arg_documentId = (args[0] as String?); + assert(arg_documentId != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncFailed was null, expected non-null String.'); + final String? arg_error = (args[1] as String?); + assert(arg_error != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantSyncFailed was null, expected non-null String.'); + try { + api.onInstantSyncFailed(arg_documentId!, arg_error!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantAuthenticationFinished$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantAuthenticationFinished was null.'); + final List args = (message as List?)!; + final String? arg_documentId = (args[0] as String?); + assert(arg_documentId != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantAuthenticationFinished was null, expected non-null String.'); + final String? arg_validJWT = (args[1] as String?); + assert(arg_validJWT != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantAuthenticationFinished was null, expected non-null String.'); + try { + api.onInstantAuthenticationFinished(arg_documentId!, arg_validJWT!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantAuthenticationFailed$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantAuthenticationFailed was null.'); + final List args = (message as List?)!; + final String? arg_documentId = (args[0] as String?); + assert(arg_documentId != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantAuthenticationFailed was null, expected non-null String.'); + final String? arg_error = (args[1] as String?); + assert(arg_error != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantAuthenticationFailed was null, expected non-null String.'); + try { + api.onInstantAuthenticationFailed(arg_documentId!, arg_error!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantDownloadFinished$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantDownloadFinished was null.'); + final List args = (message as List?)!; + final String? arg_documentId = (args[0] as String?); + assert(arg_documentId != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantDownloadFinished was null, expected non-null String.'); + try { + api.onInstantDownloadFinished(arg_documentId!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantDownloadFailed$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantDownloadFailed was null.'); + final List args = (message as List?)!; + final String? arg_documentId = (args[0] as String?); + assert(arg_documentId != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantDownloadFailed was null, expected non-null String.'); + final String? arg_error = (args[1] as String?); + assert(arg_error != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitFlutterApiCallbacks.onInstantDownloadFailed was null, expected non-null String.'); + try { + api.onInstantDownloadFailed(arg_documentId!, arg_error!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} + +class PspdfkitWidgetControllerApi { + /// Constructor for [PspdfkitWidgetControllerApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + PspdfkitWidgetControllerApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + /// Sets the value of a form field by specifying its fully qualified field name. + /// This method is deprecated. Use [PdfDocument.setFormFieldValue] instead. + Future setFormFieldValue(String value, String fullyQualifiedName) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.setFormFieldValue$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([value, fullyQualifiedName]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + /// Gets the form field value by specifying its fully qualified name. + Future getFormFieldValue(String fullyQualifiedName) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getFormFieldValue$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([fullyQualifiedName]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + /// Applies Instant document JSON to the presented document. + Future applyInstantJson(String annotationsJson) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.applyInstantJson$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([annotationsJson]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + /// Exports Instant document JSON from the presented document. + Future exportInstantJson() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.exportInstantJson$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + /// Adds the given annotation to the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + Future addAnnotation(String jsonAnnotation) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.addAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([jsonAnnotation]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + /// Removes the given annotation from the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + Future removeAnnotation(String jsonAnnotation) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.removeAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([jsonAnnotation]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + /// Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. + Future getAnnotations(int pageIndex, String type) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([pageIndex, type]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return pigeonVar_replyList[0]!; + } + } + + /// Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. + Future getAllUnsavedAnnotations() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getAllUnsavedAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return pigeonVar_replyList[0]!; + } + } + + /// Processes annotations of the given type with the provided processing + /// mode and stores the PDF at the given destination path. + Future processAnnotations(AnnotationType type, AnnotationProcessingMode processingMode, String destinationPath) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.processAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([type, processingMode, destinationPath]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Imports annotations from the XFDF file at the given path. + Future importXfdf(String xfdfString) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.importXfdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([xfdfString]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Exports annotations to the XFDF file at the given path. + Future exportXfdf(String xfdfPath) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.exportXfdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([xfdfPath]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Saves the document back to its original location if it has been changed. + /// If there were no changes to the document, the document file will not be modified. + Future save() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.save$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Sets the annotation preset configurations for the given annotation tools. + /// @param configurations A map of annotation tools and their corresponding configurations. + /// @param modifyAssociatedAnnotations Whether to modify the annotations associated with the old configuration. Only used for Android. + /// @return True if the configurations were set successfully, false otherwise. + Future setAnnotationConfigurations(Map> configurations) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.setAnnotationConfigurations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([configurations]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + /// Gets the visible rect of the given page. + /// pageIndex The index of the page. This is a zero-based index. + /// Returns a [Future] that completes with the visible rect of the given page. + Future getVisibleRect(int pageIndex) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getVisibleRect$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([pageIndex]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PdfRect?)!; + } + } + + /// Zooms to the given rect on the given page. + /// pageIndex The index of the page. This is a zero-based index. + /// rect The rect to zoom to. + /// Returns a [Future] that completes when the zoom operation is done. + Future zoomToRect(int pageIndex, PdfRect rect, bool? animated, double? duration) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.zoomToRect$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([pageIndex, rect, animated, duration]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Gets the zoom scale of the given page. + /// pageIndex The index of the page. This is a zero-based index. + /// Returns a [Future] that completes with the zoom scale of the given page. + Future getZoomScale(int pageIndex) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.getZoomScale$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([pageIndex]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as double?)!; + } + } +} + +class PdfDocumentApi { + /// Constructor for [PdfDocumentApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + PdfDocumentApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + /// Returns the page info for the given page index. + /// pageIndex The index of the page. This is a zero-based index. + Future getPageInfo(int pageIndex) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getPageInfo$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([pageIndex]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PageInfo?)!; + } + } + + /// Exports the document as a PDF. + /// options:[DocumentSaveOptions] The options to use when exporting the document. + /// Returns a [Uint8List] containing the exported PDF data. + Future exportPdf(DocumentSaveOptions? options) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.exportPdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([options]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as Uint8List?)!; + } + } + + Future> getFormField(String fieldName) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getFormField$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([fieldName]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as Map?)!.cast(); + } + } + + /// Returns a list of all form fields in the document. + Future>> getFormFields() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getFormFields$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as List?)!.cast>(); + } + } + + /// Sets the value of a form field by specifying its fully qualified field name. + Future setFormFieldValue(String value, String fullyQualifiedName) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.setFormFieldValue$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([value, fullyQualifiedName]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + /// Gets the form field value by specifying its fully qualified name. + Future getFormFieldValue(String fullyQualifiedName) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getFormFieldValue$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([fullyQualifiedName]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + /// Applies Instant document JSON to the presented document. + Future applyInstantJson(String annotationsJson) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.applyInstantJson$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([annotationsJson]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + /// Exports Instant document JSON from the presented document. + Future exportInstantJson() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.exportInstantJson$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + /// Adds the given annotation to the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + Future addAnnotation(String jsonAnnotation) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.addAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([jsonAnnotation]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + /// Removes the given annotation from the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + Future removeAnnotation(String jsonAnnotation) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.removeAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([jsonAnnotation]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } + + /// Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. + Future getAnnotations(int pageIndex, String type) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([pageIndex, type]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return pigeonVar_replyList[0]!; + } + } + + /// Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. + Future getAllUnsavedAnnotations() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.getAllUnsavedAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return pigeonVar_replyList[0]!; + } + } + + /// Imports annotations from the XFDF file at the given path. + Future importXfdf(String xfdfString) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.importXfdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([xfdfString]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Exports annotations to the XFDF file at the given path. + Future exportXfdf(String xfdfPath) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.exportXfdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([xfdfPath]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Saves the document back to its original location if it has been changed. + /// If there were no changes to the document, the document file will not be modified. + Future save(String? outputPath, DocumentSaveOptions? options) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.pspdfkit_flutter.PdfDocumentApi.save$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([outputPath, options]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } +} + +abstract class PspdfkitWidgetCallbacks { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + void onDocumentLoaded(String documentId); + + void onDocumentError(String documentId, String error); + + void onPageChanged(String documentId, int pageIndex); + + static void setUp(PspdfkitWidgetCallbacks? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onDocumentLoaded$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onDocumentLoaded was null.'); + final List args = (message as List?)!; + final String? arg_documentId = (args[0] as String?); + assert(arg_documentId != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onDocumentLoaded was null, expected non-null String.'); + try { + api.onDocumentLoaded(arg_documentId!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onDocumentError$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onDocumentError was null.'); + final List args = (message as List?)!; + final String? arg_documentId = (args[0] as String?); + assert(arg_documentId != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onDocumentError was null, expected non-null String.'); + final String? arg_error = (args[1] as String?); + assert(arg_error != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onDocumentError was null, expected non-null String.'); + try { + api.onDocumentError(arg_documentId!, arg_error!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onPageChanged$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onPageChanged was null.'); + final List args = (message as List?)!; + final String? arg_documentId = (args[0] as String?); + assert(arg_documentId != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onPageChanged was null, expected non-null String.'); + final int? arg_pageIndex = (args[1] as int?); + assert(arg_pageIndex != null, + 'Argument for dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetCallbacks.onPageChanged was null, expected non-null int.'); + try { + api.onPageChanged(arg_documentId!, arg_pageIndex!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} diff --git a/lib/src/document/document_permissions.dart b/lib/src/document/document_permissions.dart deleted file mode 100644 index e2138506..00000000 --- a/lib/src/document/document_permissions.dart +++ /dev/null @@ -1,32 +0,0 @@ -/// Copyright © 2024 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. - -enum DocumentPermissions { - /// Allow printing of document. - printing, - - /// Modify the contents of the document. - modification, - - /// Copy text and images from the document. - extract, - - /// Add or modify text annotations, fill in interactive form fields. - annotationsAndForms, - - /// Fill in existing interactive form fields (including signature fields). - fillForms, - - /// Extract text and images from the document. - extractAccessibility, - - /// Assemble the document (insert, rotate, or delete pages and create document outline items or thumbnail images). - assemble, - - /// Print high quality. - printHighQuality; -} diff --git a/lib/src/document/document_save_options.dart b/lib/src/document/document_save_options.dart deleted file mode 100644 index 3956fb50..00000000 --- a/lib/src/document/document_save_options.dart +++ /dev/null @@ -1,91 +0,0 @@ -/// Copyright © 2024 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 'package:pspdfkit_flutter/src/document/document_permissions.dart'; -import 'package:pspdfkit_flutter/src/document/pdf_version.dart'; - -/// Options for saving/exporting a document. -class DocumentSaveOptions { - /// The password is used to encrypt the document. On Web, it's used as the user password. - final String? userPassword; - - /// The owner password is used to encrypt the document and set permissions. It's only used on Web. - final String? ownerPassword; - - /// Flatten annotations and form fields into the page content. - final bool? flatten; - - /// Whether to save the document incrementally. - final bool? incremental; - - /// The permissions to set on the document. See [DocumentPermissions] for more information. - final List? permissions; - - /// The PDF version to save the document as. - final PdfVersion? pdfVersion; - - /// Whether to exclude annotations from the exported document. - final bool? excludeAnnotations; - - /// Whether to exclude annotations that have the noPrint flag set to true from the exported document (Standalone only) - final bool? saveForPrinting; - - ///// Whether to include comments in the exported document (Server-Backed only). - final bool? includeComments; - - /// Whether tp allow you to export a PDF in PDF/A format. - final dynamic outputFormat; - - /// Whether to optimize the document for the web. - final bool? optimize; - - DocumentSaveOptions( - {this.userPassword, - this.ownerPassword, - this.flatten, - this.incremental, - this.permissions, - this.pdfVersion, - this.excludeAnnotations, - this.saveForPrinting, - this.includeComments, - this.outputFormat, - this.optimize}); - - /// Converts the options to a map that can be passed to the platform channel. - Map toMap() { - return { - 'userPassword': userPassword, - 'ownerPassword': ownerPassword, - 'flatten': flatten, - 'incremental': incremental, - 'permissions': permissions?.map((e) => e.name).toList(), - 'pdfVersion': pdfVersion?.name, - }..removeWhere((key, value) => value == null); - } - - /// Converts the options to a map that can be passed to the web function call. - Map toWebOptions() { - return { - 'flatten': flatten, - 'incremental': incremental, - 'excludeAnnotations': excludeAnnotations, - 'saveForPrinting': saveForPrinting, - 'outputFormat': outputFormat, - 'optimize': optimize, - 'includeComments': includeComments, - 'permissions': { - 'documentPermissions': permissions?.map((e) => e.name).toList() ?? [], - 'userPassword': userPassword, - 'ownerPassword': ownerPassword, - }..removeWhere((key, value) => value == null) - }..removeWhere((key, value) => - value == null || - value is List && value.isEmpty || - value is Map && value.isEmpty); - } -} diff --git a/lib/src/document/document_save_options_extension.dart b/lib/src/document/document_save_options_extension.dart new file mode 100644 index 00000000..8aa5b8ca --- /dev/null +++ b/lib/src/document/document_save_options_extension.dart @@ -0,0 +1,44 @@ +/// Copyright © 2024 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 '../../pspdfkit.dart'; + +/// Options for saving/exporting a document. +extension DocumentSaveOptionsX on DocumentSaveOptions { + /// Converts the options to a map that can be passed to the platform channel. + Map toMap() { + return { + 'userPassword': userPassword, + 'ownerPassword': ownerPassword, + 'flatten': flatten, + 'incremental': incremental, + 'permissions': permissions?.map((e) => e).toList(), + 'pdfVersion': pdfVersion?.name, + }..removeWhere((key, value) => value == null); + } + + /// Converts the options to a map that can be passed to the web function call. + Map toWebOptions() { + return { + 'flatten': flatten, + 'incremental': incremental, + 'excludeAnnotations': excludeAnnotations, + 'saveForPrinting': saveForPrinting, + 'outputFormat': outputFormat, + 'optimize': optimize, + 'includeComments': includeComments, + 'permissions': { + 'documentPermissions': permissions?.map((e) => e).toList() ?? [], + 'userPassword': userPassword, + 'ownerPassword': ownerPassword, + }..removeWhere((key, value) => value == null) + }..removeWhere((key, value) => + value == null || + value is List && value.isEmpty || + value is Map && value.isEmpty); + } +} diff --git a/lib/src/document/page_info.dart b/lib/src/document/page_info.dart deleted file mode 100644 index aa732584..00000000 --- a/lib/src/document/page_info.dart +++ /dev/null @@ -1,56 +0,0 @@ -/// Copyright © 2024 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. - -class PageInfo { - PageInfo({ - required this.pageIndex, - required this.height, - required this.width, - required this.rotation, - this.label = '', - }); - - /// The index of the page. This is a zero-based index. - final int pageIndex; - - /// The height of the page in points. - final double height; - - /// The width of the page in points. - final double width; - - /// The rotation of the page in degrees. - final int rotation; - - /// The label of the page. - final String label; - - factory PageInfo.fromJson(dynamic pageInfo) { - return PageInfo( - pageIndex: pageInfo['index'], - height: pageInfo['height'], - width: pageInfo['width'], - rotation: pageInfo['rotation'], - label: pageInfo['label'], - ); - } - - factory PageInfo.fromWebJson(pageInfo) { - return PageInfo( - pageIndex: pageInfo['index'], - height: pageInfo['height'], - width: pageInfo['width'], - rotation: pageInfo['rotation'], - label: pageInfo['label'], - ); - } - - @override - String toString() { - return 'PageInfo{pageIndex: $pageIndex, height: $height, width: $width, rotation: $rotation, label: $label}'; - } -} diff --git a/lib/src/document/pdf_document.dart b/lib/src/document/pdf_document.dart index e920210f..3f484b59 100644 --- a/lib/src/document/pdf_document.dart +++ b/lib/src/document/pdf_document.dart @@ -7,9 +7,7 @@ import 'dart:typed_data'; -import 'package:pspdfkit_flutter/src/document/document_save_options.dart'; -import 'package:pspdfkit_flutter/src/document/page_info.dart'; -import 'package:pspdfkit_flutter/src/forms/form_field.dart'; +import '../../pspdfkit.dart'; abstract class PdfDocument { final String documentId; @@ -30,4 +28,40 @@ abstract class PdfDocument { /// Returns a list of all form fields in the document. Future> getFormFields(); + + /// Sets the value of a form field by specifying its fully qualified field name. + Future setFormFieldValue(String value, String fullyQualifiedName); + + /// Gets the form field value by specifying its fully qualified name. + Future getFormFieldValue(String fullyQualifiedName); + + /// Applies Instant document JSON to the presented document. + Future applyInstantJson(String annotationsJson); + + /// Exports Instant document JSON from the presented document. + Future exportInstantJson(); + + /// Adds the given annotation to the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + Future addAnnotation(String jsonAnnotation); + + /// Removes the given annotation from the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + Future removeAnnotation(String jsonAnnotation); + + /// Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. + Future getAnnotations(int pageIndex, String type); + + /// Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. + Future getAllUnsavedAnnotations(); + + /// Imports annotations from the XFDF file at the given path. + Future importXfdf(String xfdfString); + + /// Exports annotations to the XFDF file at the given path. + Future exportXfdf(String xfdfPath); + + /// Saves the document back to its original location if it has been changed. + /// If there were no changes to the document, the document file will not be modified. + Future save(String? outputPath, DocumentSaveOptions? options); } diff --git a/lib/src/document/pdf_document_native.dart b/lib/src/document/pdf_document_native.dart index 0fe2f4c0..f2a67fe4 100644 --- a/lib/src/document/pdf_document_native.dart +++ b/lib/src/document/pdf_document_native.dart @@ -5,57 +5,42 @@ /// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. /// This notice may not be removed from this file. -import 'package:flutter/services.dart'; -import 'package:pspdfkit_flutter/src/document/page_info.dart'; +import 'dart:convert'; -import '../forms/form_field.dart'; -import 'document_save_options.dart'; -import 'pdf_document.dart'; +import 'package:flutter/foundation.dart'; +import 'package:pspdfkit_flutter/pspdfkit.dart'; class PdfDocumentNative extends PdfDocument { - late final MethodChannel _channel; + late final PdfDocumentApi _api; - PdfDocumentNative( - {required super.documentId, required MethodChannel iosMethodChannel}) { - _channel = MethodChannel('com.pspdfkit.document.$documentId'); + PdfDocumentNative({required super.documentId, required PdfDocumentApi api}) { + _api = api; } @override - Future getPageInfo(int pageIndex) => - _channel.invokeMethod('getPageInfo', { - 'pageIndex': pageIndex, - }).then((results) { - if (results == null) { - throw Exception('Page info is null'); - } - return PageInfo.fromJson(results); - }).catchError((error) { - throw Exception('Error getting page info: $error'); - }); + Future getPageInfo(int pageIndex) { + try { + return _api.getPageInfo(pageIndex); + } catch (e) { + debugPrint('Error getting page info: $e'); + throw Exception('Error getting page info: $e'); + } + } @override Future exportPdf({DocumentSaveOptions? options}) { - return _channel.invokeMethod('exportPdf', { - 'options': options?.toMap() ?? {}, - }).then((results) { - if (results == null) { - throw Exception('Exported PDF is null'); - } - return Uint8List.fromList(results.cast()); - }).catchError((error) { - throw Exception('Error exporting PDF: $error'); - }); + try { + return _api.exportPdf(options); + } catch (e) { + debugPrint('Error exporting PDF: $e'); + throw Exception('Error exporting PDF: $e'); + } } @override Future getFormField(String fieldName) { - return _channel.invokeMethod('getFormField', { - 'fieldName': fieldName, - }).then((results) { - if (results == null) { - throw Exception('Form field is null'); - } - return PdfFormField.fromMap(results); + return _api.getFormField(fieldName).then((result) { + return PdfFormField.fromMap(result.cast()); }).catchError((error) { throw Exception('Error getting form field: $error'); }); @@ -63,14 +48,84 @@ class PdfDocumentNative extends PdfDocument { @override Future> getFormFields() { - return _channel.invokeMethod('getFormFields').then((results) { - if (results == null) { - throw Exception('Form fields are null'); - } - return List.from( - results.map((result) => PdfFormField.fromMap(result))); + return _api.getFormFields().then((results) { + return results + .map((result) => PdfFormField.fromMap(result.cast())) + .toList(); }).catchError((error) { throw Exception('Error getting form fields: $error'); }); } + + @override + Future addAnnotation(String jsonAnnotation) { + return _api.addAnnotation(jsonAnnotation); + } + + @override + Future applyInstantJson(String annotationsJson) { + return _api.applyInstantJson(annotationsJson); + } + + @override + Future exportInstantJson() { + return _api.exportInstantJson(); + } + + @override + Future exportXfdf(String xfdfPath) { + return _api.exportXfdf(xfdfPath); + } + + @override + Future getAllUnsavedAnnotations() { + return _api.getAllUnsavedAnnotations(); + } + + @override + Future getAnnotations(int pageIndex, String type) { + return _api.getAnnotations(pageIndex, type).then((results) { + if (results is List) { + return results.map((result) { + if (result is Map) { + return result; + } else if (result is String) { + // Convert string to map + return jsonDecode(result); + } else { + throw Exception('Invalid annotation type: $result'); + } + }).toList(); + } else { + throw Exception('Invalid annotations type: $results'); + } + }).catchError((error) { + throw Exception('Error getting annotations: $error'); + }); + } + + @override + Future getFormFieldValue(String fullyQualifiedName) { + return _api.getFormFieldValue(fullyQualifiedName); + } + + @override + Future importXfdf(String xfdfString) { + return _api.importXfdf(xfdfString); + } + + @override + Future removeAnnotation(String jsonAnnotation) { + return _api.removeAnnotation(jsonAnnotation); + } + + @override + Future save(String? outputPath, DocumentSaveOptions? options) { + return _api.save(outputPath, options); + } + + @override + Future setFormFieldValue(String value, String fullyQualifiedName) { + return _api.setFormFieldValue(value, fullyQualifiedName); + } } diff --git a/lib/src/document/pdf_document_web.dart b/lib/src/document/pdf_document_web.dart index 3a3baa3c..5447e039 100644 --- a/lib/src/document/pdf_document_web.dart +++ b/lib/src/document/pdf_document_web.dart @@ -5,14 +5,11 @@ /// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. /// This notice may not be removed from this file. +import 'dart:convert'; import 'dart:typed_data'; -import 'package:pspdfkit_flutter/src/document/page_info.dart'; -import 'package:pspdfkit_flutter/src/web/pspdfkit_web_instance.dart'; - -import '../forms/form_field.dart'; -import 'document_save_options.dart'; -import 'pdf_document.dart'; +import '../../pspdfkit.dart'; +import '../web/pspdfkit_web_instance.dart'; class PdfDocumentWeb extends PdfDocument { final PspdfkitWebInstance _instance; @@ -40,4 +37,67 @@ class PdfDocumentWeb extends PdfDocument { Future> getFormFields() { return _instance.getFormFields(); } + + @override + Future addAnnotation(String jsonAnnotation) { + return _instance + .addAnnotation(jsonDecode(jsonAnnotation)) + .then((value) => true); + } + + @override + Future applyInstantJson(String annotationsJson) { + return _instance + .applyInstantJson(jsonDecode(annotationsJson)) + .then((value) => true); + } + + @override + Future exportInstantJson() { + return _instance.exportInstantJson().then((value) => jsonEncode(value)); + } + + @override + Future exportXfdf(String xfdfPath) { + return _instance.exportXfdf(xfdfPath).then((value) => true); + } + + @override + Future getAllUnsavedAnnotations() { + return _instance.getAllAnnotations(); + } + + @override + Future getAnnotations(int pageIndex, String type) { + return _instance.getAnnotations(pageIndex, type).then((value) => value); + } + + @override + Future getFormFieldValue(String fullyQualifiedName) { + return _instance.getFormFieldValue(fullyQualifiedName); + } + + @override + Future importXfdf(String xfdfString) { + return _instance.importXfdf(xfdfString).then((value) => true); + } + + @override + Future removeAnnotation(Object jsonAnnotation) { + return _instance + .removeAnnotation(jsonDecode(jsonAnnotation.toString())) + .then((value) => true); + } + + @override + Future save(String? outputPath, DocumentSaveOptions? options) { + return _instance.save().then((value) => true); + } + + @override + Future setFormFieldValue(String value, String fullyQualifiedName) { + return _instance + .setFormFieldValue(value, fullyQualifiedName) + .then((value) => true); + } } diff --git a/lib/src/document/pdf_version.dart b/lib/src/document/pdf_version.dart deleted file mode 100644 index 1dea7d7f..00000000 --- a/lib/src/document/pdf_version.dart +++ /dev/null @@ -1,18 +0,0 @@ -/// Copyright © 2024 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 PDF version of a document. -enum PdfVersion { - pdf_1_0, - pdf_1_1, - pdf_1_2, - pdf_1_3, - pdf_1_4, - pdf_1_5, - pdf_1_6, - pdf_1_7, -} diff --git a/lib/src/forms/combobox_form_field.dart b/lib/src/forms/combobox_form_field.dart index ebd3a42e..8bafa92b 100644 --- a/lib/src/forms/combobox_form_field.dart +++ b/lib/src/forms/combobox_form_field.dart @@ -7,8 +7,7 @@ /// This notice may not be removed from this file. /// -import 'package:pspdfkit_flutter/src/forms/form_field.dart'; -import 'package:pspdfkit_flutter/src/forms/pdf_form_options.dart'; +import 'package:pspdfkit_flutter/pspdfkit.dart'; class ComboBoxFormField extends PdfFormField { final List defaultValues; @@ -26,7 +25,16 @@ class ComboBoxFormField extends PdfFormField { return ComboBoxFormField( defaultValues: List.from(map['defaultValues']), selectedIndices: List.from(map['selectedIndices']), - options: PdfFormOption.listFromMap(map['options']), + options: _populateOptions(map['options']), values: List.from(map['values'])); } + + static List _populateOptions(dynamic json) { + return json + .map((e) => PdfFormOption( + value: e['value'], + label: e['label'], + )) + .toList(); + } } diff --git a/lib/src/forms/form_field.dart b/lib/src/forms/form_field.dart index a229c070..64d005fa 100644 --- a/lib/src/forms/form_field.dart +++ b/lib/src/forms/form_field.dart @@ -1,21 +1,5 @@ -/// -/// Copyright © 2024 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 'package:pspdfkit_flutter/src/forms/button_form_field.dart'; -import 'package:pspdfkit_flutter/src/forms/form_field_type.dart'; -import 'package:pspdfkit_flutter/src/forms/listbox_form_field.dart'; -import 'package:pspdfkit_flutter/src/forms/radio_button_form_field.dart'; - -import 'checkbox_form_field.dart'; -import 'combobox_form_field.dart'; -import 'signature_form_field.dart'; -import 'text_form_field.dart'; +import 'package:pspdfkit_flutter/src/forms/form_field_type_extension.dart'; +import '../../pspdfkit.dart'; abstract class PdfFormField { late String _name; diff --git a/lib/src/forms/form_field_type_extension.dart b/lib/src/forms/form_field_type_extension.dart new file mode 100644 index 00000000..3799e0e0 --- /dev/null +++ b/lib/src/forms/form_field_type_extension.dart @@ -0,0 +1,33 @@ +import '../../pspdfkit.dart'; + +/// +/// Copyright © 2024 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. +/// + +extension PdfFormFieldTypesExtension on PdfFormFieldTypes { + String get nativeName { + switch (this) { + case PdfFormFieldTypes.text: + return 'TEXT'; + case PdfFormFieldTypes.checkbox: + return 'CHECKBOX'; + case PdfFormFieldTypes.radioButton: + return 'RADIOBUTTON'; + case PdfFormFieldTypes.comboBox: + return 'COMBOBOX'; + case PdfFormFieldTypes.listBox: + return 'LISTBOX'; + case PdfFormFieldTypes.signature: + return 'SIGNATURE'; + case PdfFormFieldTypes.button: + return 'PUSHBUTTON'; + case PdfFormFieldTypes.unknown: + return 'UNDEFINED'; + } + } +} diff --git a/lib/src/forms/forms.dart b/lib/src/forms/forms.dart index e681ad97..50838d73 100644 --- a/lib/src/forms/forms.dart +++ b/lib/src/forms/forms.dart @@ -4,7 +4,5 @@ export 'radio_button_form_field.dart'; export 'text_form_field.dart'; export 'signature_form_field.dart'; export 'button_form_field.dart'; -export 'pdf_form_options.dart'; export 'listbox_form_field.dart'; export 'combobox_form_field.dart'; -export 'form_field_type.dart'; diff --git a/lib/src/forms/listbox_form_field.dart b/lib/src/forms/listbox_form_field.dart index eda53602..1870553c 100644 --- a/lib/src/forms/listbox_form_field.dart +++ b/lib/src/forms/listbox_form_field.dart @@ -7,9 +7,7 @@ /// This notice may not be removed from this file. /// -import 'package:pspdfkit_flutter/src/forms/form_field.dart'; - -import 'pdf_form_options.dart'; +import '../../pspdfkit.dart'; class ListBoxFormField extends PdfFormField { final List defaultValues; @@ -24,7 +22,16 @@ class ListBoxFormField extends PdfFormField { factory ListBoxFormField.fromMap(dynamic map) { return ListBoxFormField( defaultValues: List.from(map['defaultValues']), - options: PdfFormOption.listFromMap(map['options']), + options: _populateOptions(map['options']), values: List.from(map['values'])); } + + static List _populateOptions(dynamic json) { + return json + .map((e) => PdfFormOption( + value: e['value'], + label: e['label'], + )) + .toList(); + } } diff --git a/lib/src/processor/annotation_processing_mode.dart b/lib/src/processor/annotation_processing_mode.dart deleted file mode 100644 index 622e87e4..00000000 --- a/lib/src/processor/annotation_processing_mode.dart +++ /dev/null @@ -1,6 +0,0 @@ -enum AnnotationProcessingMode { - flatten, - remove, - embed, - print, -} diff --git a/lib/src/pspdfkit_flutter_api_impl.dart b/lib/src/pspdfkit_flutter_api_impl.dart new file mode 100644 index 00000000..9c4b1a8c --- /dev/null +++ b/lib/src/pspdfkit_flutter_api_impl.dart @@ -0,0 +1,296 @@ +import 'dart:io'; + +import 'package:flutter/services.dart'; +import 'package:pspdfkit_flutter/pspdfkit.dart'; +import 'package:pspdfkit_flutter/src/pspdfkit_flutter_platform_interface.dart'; + +class PspdfkitFlutterApiImpl + implements PspdfkitFlutterPlatform, PspdfkitFlutterApiCallbacks { + late PspdfkitApi _pspdfkitApi = PspdfkitApi(); + PspdfkitFlutterApiImpl() { + var messageChannel = const MethodChannel('com.pspdfkit.global'); + + _pspdfkitApi = PspdfkitApi( + binaryMessenger: messageChannel.binaryMessenger, + messageChannelSuffix: 'pspdfkit'); + + PspdfkitFlutterApiCallbacks.setUp(this, + binaryMessenger: messageChannel.binaryMessenger, + messageChannelSuffix: 'pspdfkit'); + } + + @override + VoidCallback? flutterPdfActivityOnPause; + + @override + PspdfkitDocumentLoadedCallback? flutterPdfDocumentLoaded; + + @override + VoidCallback? flutterPdfFragmentAdded; + + @override + InstantAuthenticationFailedCallback? instantAuthenticationFailed; + + @override + InstantAuthenticationFinishedCallback? instantAuthenticationFinished; + + @override + InstantDownloadFailedCallback? instantDownloadFailed; + + @override + InstantDownloadFinishedCallback? instantDownloadFinished; + + @override + InstantSyncFailedCallback? instantSyncFailed; + + @override + InstantSyncFinishedCallback? instantSyncFinished; + + @override + InstantSyncStartedCallback? instantSyncStarted; + + @override + VoidCallback? pdfViewControllerDidDismiss; + + @override + VoidCallback? pdfViewControllerWillDismiss; + + @override + Future addAnnotation(jsonAnnotation) { + return _pspdfkitApi.addAnnotation(jsonAnnotation); + } + + @override + Future applyInstantJson(String annotationsJson) { + return _pspdfkitApi.applyInstantJson(annotationsJson); + } + + @override + String get authorName => throw UnimplementedError(); + + @override + Future checkAndroidWriteExternalStoragePermission() { + return _pspdfkitApi.checkAndroidWriteExternalStoragePermission(); + } + + @override + List get defaultWebToolbarItems => []; + + @override + Future exportInstantJson() { + return _pspdfkitApi.exportInstantJson(); + } + + @override + Future exportXfdf(String xfdfPath) { + return _pspdfkitApi.exportXfdf(xfdfPath); + } + + @override + Future getAllUnsavedAnnotations() { + return _pspdfkitApi.getAllUnsavedAnnotations(); + } + + @override + Future getAnnotations(int pageIndex, String type) { + return _pspdfkitApi.getAnnotations(pageIndex, type); + } + + @override + Future getFormFieldValue(String fullyQualifiedName) { + return _pspdfkitApi.getFormFieldValue(fullyQualifiedName); + } + + @override + Future getFrameworkVersion() { + return _pspdfkitApi.getFrameworkVersion(); + } + + @override + Future getTemporaryDirectory() { + return _pspdfkitApi.getTemporaryDirectory().then((path) => Directory(path)); + } + + @override + Future importXfdf(String xfdfString) { + return _pspdfkitApi.importXfdf(xfdfString); + } + + @override + Future openAndroidSettings() { + return _pspdfkitApi.openAndroidSettings(); + } + + @override + Future present(String document, {dynamic configuration}) { + Map? configurationMap; + if (configuration is PdfConfiguration) { + configurationMap = (configuration).toMap(); + } else if (configuration is Map) { + configurationMap = configuration; + } else { + configurationMap = {}; + } + return _pspdfkitApi.present( + document, + configuration: configurationMap.cast(), + ); + } + + @override + Future presentInstant(String serverUrl, String jwt, [configuration]) { + Map? configurationMap; + if (configuration is PdfConfiguration) { + configurationMap = (configuration).toMap(); + } else if (configuration is Map) { + configurationMap = configuration; + } else { + configurationMap = {}; + } + return _pspdfkitApi.presentInstant(serverUrl, jwt, + configuration: configurationMap as Map?); + } + + @override + Future processAnnotations(AnnotationType type, + AnnotationProcessingMode processingMode, String destinationPath) { + return _pspdfkitApi.processAnnotations( + type, processingMode, destinationPath); + } + + @override + Future removeAnnotation(jsonAnnotation) { + return _pspdfkitApi.removeAnnotation(jsonAnnotation); + } + + @override + Future + requestAndroidWriteExternalStoragePermission() { + return _pspdfkitApi.requestAndroidWriteExternalStoragePermission(); + } + + @override + Future save() { + return _pspdfkitApi.save(); + } + + @override + Future setAnnotationPresetConfigurations( + Map configurations) { + return _pspdfkitApi.setAnnotationPresetConfigurations(configurations); + } + + @override + Future setDelayForSyncingLocalChanges(double delay) { + return _pspdfkitApi.setDelayForSyncingLocalChanges(delay); + } + + @override + Future setFormFieldValue(String value, String fullyQualifiedName) { + return _pspdfkitApi.setFormFieldValue(value, fullyQualifiedName); + } + + @override + Future setLicenseKey(String? licenseKey) { + return _pspdfkitApi.setLicenseKey(licenseKey); + } + + @override + Future setLicenseKeys( + String? androidLicenseKey, String? iOSLicenseKey, String? webLicenseKey) { + return _pspdfkitApi.setLicenseKeys( + androidLicenseKey, iOSLicenseKey, webLicenseKey); + } + + @override + Future setListenToServerChanges(bool listen) { + return _pspdfkitApi.setListenToServerChanges(listen); + } + + @override + Future syncAnnotations() { + return _pspdfkitApi.syncAnnotations(); + } + + @override + void onDocumentLoaded(String documentId) { + flutterPdfDocumentLoaded?.call(documentId); + } + + @override + void onInstantAuthenticationFailed(String documentId, String error) { + instantAuthenticationFailed?.call(documentId, error); + } + + @override + void onInstantAuthenticationFinished(String documentId, String validJWT) { + instantAuthenticationFinished?.call(documentId, validJWT); + } + + @override + void onInstantDownloadFailed(String documentId, String error) { + instantDownloadFailed?.call(documentId, error); + } + + @override + void onInstantDownloadFinished(String documentId) { + instantDownloadFinished?.call(documentId); + } + + @override + void onInstantSyncFailed(String documentId, String error) { + instantSyncFailed?.call(documentId, error); + } + + @override + void onInstantSyncFinished(String documentId) { + instantSyncFinished?.call(documentId); + } + + @override + void onInstantSyncStarted(String documentId) { + instantSyncStarted?.call(documentId); + } + + @override + void onPdfActivityOnPause() { + flutterPdfActivityOnPause?.call(); + } + + @override + void onPdfFragmentAdded() { + flutterPdfFragmentAdded?.call(); + } + + @override + void onPdfViewControllerDidDismiss() { + pdfViewControllerDidDismiss?.call(); + } + + @override + void onPdfViewControllerWillDismiss() { + pdfViewControllerWillDismiss?.call(); + } + + @override + Future generatePdf(List pages, String outPutFile, + [Map? options]) { + var pagesMaps = + pages.map((page) => page.toMap().cast()).toList(); + return _pspdfkitApi.generatePdf(pagesMaps, outPutFile); + } + + @override + Future generatePdfFromHtmlString(String html, String outPutFile, + [Map? options]) { + return _pspdfkitApi.generatePdfFromHtmlString( + html, outPutFile, options?.cast()); + } + + @override + Future generatePdfFromHtmlUri(Uri htmlUri, String outPutFile, + [Map? options]) { + return _pspdfkitApi.generatePdfFromHtmlUri( + htmlUri.toString(), outPutFile, options?.cast()); + } +} diff --git a/lib/src/pspdfkit_flutter_method_channel.dart b/lib/src/pspdfkit_flutter_method_channel.dart index e9385ae8..72b99dea 100644 --- a/lib/src/pspdfkit_flutter_method_channel.dart +++ b/lib/src/pspdfkit_flutter_method_channel.dart @@ -13,7 +13,9 @@ import 'package:flutter/services.dart'; import 'package:pspdfkit_flutter/pspdfkit.dart'; import 'pspdfkit_flutter_platform_interface.dart'; -/// An implementation of [PspdfkitFlutterPlatform] that uses method channels. +/// An implementation of [PspdfkitFlutterPlatform] that +@Deprecated( + 'This class is deprecated and will be removed in the future, Use [PspdfkitFlutterApiImpl] instead') class MethodChannelPspdfkitFlutter extends PspdfkitFlutterPlatform { /// The method channel used to interact with the native platform. @visibleForTesting @@ -42,10 +44,7 @@ class MethodChannelPspdfkitFlutter extends PspdfkitFlutterPlatform { /// Loads a [document] with a supported format using a given [configuration]. @override - Future present(String document, - {dynamic configuration, - MeasurementScale? measurementScale, - MeasurementPrecision? measurementPrecision}) async { + Future present(String document, {dynamic configuration}) async { Map pdfConfiguration; if (configuration == null) { @@ -62,8 +61,6 @@ class MethodChannelPspdfkitFlutter extends PspdfkitFlutterPlatform { return await methodChannel.invokeMethod('present', { 'document': document, 'configuration': pdfConfiguration, - 'measurementScale': measurementScale?.toMap(), - 'measurementPrecision': measurementPrecision?.name, }); } @@ -165,8 +162,8 @@ class MethodChannelPspdfkitFlutter extends PspdfkitFlutterPlatform { /// Imports annotations from the XFDF file at the given path. @override - Future importXfdf(String xfdfPath) async => methodChannel - .invokeMethod('importXfdf', {'xfdfPath': xfdfPath}); + Future importXfdf(String xfdfString) async => methodChannel + .invokeMethod('importXfdf', {'xfdfPath': xfdfString}); /// Exports annotations to the XFDF file at the given path. @override @@ -397,4 +394,22 @@ class MethodChannelPspdfkitFlutter extends PspdfkitFlutterPlatform { @override List get defaultWebToolbarItems => []; + + @override + Future generatePdf(List pages, String outPutFile, + [Map? options]) { + throw UnimplementedError(); + } + + @override + Future generatePdfFromHtmlString(String html, String outPutFile, + [Map? options]) { + throw UnimplementedError(); + } + + @override + Future generatePdfFromHtmlUri(Uri htmlUri, String outPutFile, + [Map? options]) { + throw UnimplementedError(); + } } diff --git a/lib/src/pspdfkit_flutter_platform_interface.dart b/lib/src/pspdfkit_flutter_platform_interface.dart index e9ead019..fd0cc068 100644 --- a/lib/src/pspdfkit_flutter_platform_interface.dart +++ b/lib/src/pspdfkit_flutter_platform_interface.dart @@ -11,6 +11,8 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:pspdfkit_flutter/pspdfkit.dart'; +import 'package:pspdfkit_flutter/src/pspdfkit_flutter_api_impl.dart'; + import 'pspdfkit_flutter_method_channel.dart'; typedef InstantSyncStartedCallback = void Function(String? documentId); @@ -33,11 +35,13 @@ abstract class PspdfkitFlutterPlatform extends PlatformInterface { static final Object _token = Object(); - static PspdfkitFlutterPlatform _instance = MethodChannelPspdfkitFlutter(); + static PspdfkitFlutterPlatform _instance = Pspdfkit.useLegacy + ? MethodChannelPspdfkitFlutter() + : PspdfkitFlutterApiImpl(); /// The default instance of [PspdfkitFlutterPlatform] to use. /// - /// Defaults to [MethodChannelPspdfkitFlutter]. + /// Defaults to [PspdfkitFlutterApiImpl]. static PspdfkitFlutterPlatform get instance => _instance; /// Platform-specific implementations should set this with their own @@ -62,12 +66,7 @@ abstract class PspdfkitFlutterPlatform extends PlatformInterface { String? androidLicenseKey, String? iOSLicenseKey, String? webLicenseKey); /// Loads a [document] with a supported format using a given [configuration]. - Future present(String document, - {dynamic configuration, - @Deprecated('Use setMeasurementConfiguration instead.') - MeasurementScale? measurementScale, - @Deprecated('Use setMeasurementConfiguration instead.') - MeasurementPrecision? measurementPrecision}); + Future present(String document, {dynamic configuration}); /// Loads an Instant document from a server [serverUrl] with using a[jwt] in a native Instant PDFViewer. /// @@ -115,7 +114,7 @@ abstract class PspdfkitFlutterPlatform extends PlatformInterface { ); /// Imports annotations from the XFDF file at the given path. - Future importXfdf(String xfdfPath); + Future importXfdf(String xfdfString); /// Exports annotations to the XFDF file at the given path. Future exportXfdf(String xfdfPath); @@ -124,14 +123,14 @@ abstract class PspdfkitFlutterPlatform extends PlatformInterface { /// If there were no changes to the document, the document file will not be modified. Future save(); - /// Sets a delay for synchronising local changes to the Instant server. + /// Sets a delay for synchronizing local changes to the Instant server. /// [delay] is the delay in milliseconds. Future setDelayForSyncingLocalChanges(double delay); /// Enable or disable listening to Instant server changes. Future setListenToServerChanges(bool listen); - /// Manually triggers synchronisation. + /// Manually triggers synchronization. Future syncAnnotations(); /// Checks the external storage permission for writing on Android only. @@ -147,6 +146,30 @@ abstract class PspdfkitFlutterPlatform extends PlatformInterface { Future setAnnotationPresetConfigurations( Map configurations); + //. Generate a PDF from the given HTML string. + /// [html]: The HTML string to be converted to PDF. + /// [outPutFile]: The path to the output file. + /// [options]: A map of options that can be used to customize the PDF generation. + /// Returns the path to the generated PDF file or null if the input is invalid or if the PDF generation fails. + Future generatePdfFromHtmlString(String html, String outPutFile, + [Map? options]); + + /// Generates a PDF from the given HTML URI. + /// [htmlUri]: The URI to the HTML file to be converted to PDF. The URI can be for a local file or a remote file. + /// [outPutFile]: The path to the output file. + /// [options]: A map of options that can be used to customize the PDF generation. + /// Returns the path to the generated PDF file or null if the input is invalid or if the PDF generation fails. + Future generatePdfFromHtmlUri(Uri htmlUri, String outPutFile, + [Map? options]); + + /// Generates a PDF from the given list of pages. + /// [pages]: The list of pages to be converted to PDF. + /// [outPutFile]: The path to the output file. + /// Returns the path to the generated PDF file or null if the input is invalid or if the PDF generation fails. + /// The [options] parameter is a map of options that can be used to customize the PDF generation. + Future generatePdf(List pages, String outPutFile, + [Map? options]); + /// Path to the temporary directory on the device that is not backed up and is /// suitable for storing caches of downloaded files. /// diff --git a/lib/src/pspdfkit_flutter_web.dart b/lib/src/pspdfkit_flutter_web.dart index 391c507d..3ac30dc6 100644 --- a/lib/src/pspdfkit_flutter_web.dart +++ b/lib/src/pspdfkit_flutter_web.dart @@ -19,7 +19,8 @@ import 'pspdfkit_flutter_platform_interface.dart'; /// A web implementation of the PspdfkitFlutterPlatform of the PspdfkitFlutter plugin. class PspdfkitFlutterWeb extends PspdfkitFlutterPlatform { - static const String _notSupportedOnWebMessage = 'Not supported on web'; + static const String _notSupportedOnWebMessage = + 'Not supported on web, Please use PspdfkitWidget instead.'; /// Constructs a PspdfkitFlutterWeb PspdfkitFlutterWeb(); @@ -69,7 +70,7 @@ class PspdfkitFlutterWeb extends PspdfkitFlutterPlatform { } @override - Future importXfdf(String xfdfPath) { + Future importXfdf(String xfdfString) { throw UnimplementedError(_notSupportedOnWebMessage); } @@ -167,4 +168,22 @@ class PspdfkitFlutterWeb extends PspdfkitFlutterPlatform { @override List get defaultWebToolbarItems => PSPDFKitWeb.defaultToolbarItems; + + @override + Future generatePdf(List pages, String outPutFile, + [Map? options]) { + throw UnimplementedError(); + } + + @override + Future generatePdfFromHtmlString(String html, String outPutFile, + [Map? options]) { + throw UnimplementedError(_notSupportedOnWebMessage); + } + + @override + Future generatePdfFromHtmlUri(Uri htmlUri, String outPutFile, + [Map? options]) { + throw UnimplementedError(_notSupportedOnWebMessage); + } } diff --git a/lib/src/pspdfkit_processor.dart b/lib/src/pspdfkit_processor.dart index aa2410c3..5b32e535 100644 --- a/lib/src/pspdfkit_processor.dart +++ b/lib/src/pspdfkit_processor.dart @@ -1,3 +1,8 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; + +import 'processor/processor.dart'; + /// /// Copyright © 2018-2024 PSPDFKit GmbH. All rights reserved. /// @@ -7,14 +12,18 @@ /// This notice may not be removed from this file. /// -part of pspdfkit; - const convertorDocumentTitle = 'documentTitle'; const androidConvertorBaseUrl = 'baseUrl'; const iosConvertorPageNumber = 'numberOfPages'; const androidConvertorIsJavascriptEnabled = 'enableJavaScript'; /// This class is used to generate PDF documents from HTML,templates, patterns and images. +@Deprecated( + ''' + This class will be removed in the next major version of the plugin. + Use [Pspdfkit.generatePdf] instead. + ''', +) class PspdfkitProcessor { final MethodChannel _channel; static PspdfkitProcessor? _instance; diff --git a/lib/src/web/models/pspdfkit_web_toolbar_item_type.dart b/lib/src/web/models/pspdfkit_web_toolbar_item_type.dart index b2bc726b..4fc10e29 100644 --- a/lib/src/web/models/pspdfkit_web_toolbar_item_type.dart +++ b/lib/src/web/models/pspdfkit_web_toolbar_item_type.dart @@ -54,7 +54,8 @@ enum PspdfkitWebToolbarItemType { callout, responsiveGroup, custom, - measurements + measurements, + linearizedDownloadIndicator } extension WebToolbarItemTypeX on PspdfkitWebToolbarItemType { @@ -154,6 +155,8 @@ extension WebToolbarItemTypeX on PspdfkitWebToolbarItemType { return 'custom'; case PspdfkitWebToolbarItemType.measurements: return 'measure'; + case PspdfkitWebToolbarItemType.linearizedDownloadIndicator: + return 'linearized-download-indicator'; } } } diff --git a/lib/src/web/pspdfkit_web_instance.dart b/lib/src/web/pspdfkit_web_instance.dart index ca040b2f..b1cdf163 100644 --- a/lib/src/web/pspdfkit_web_instance.dart +++ b/lib/src/web/pspdfkit_web_instance.dart @@ -14,8 +14,8 @@ import 'dart:js'; import 'dart:typed_data'; import 'package:flutter/painting.dart'; import 'package:pspdfkit_flutter/pspdfkit.dart'; +import 'package:pspdfkit_flutter/src/document/document_save_options_extension.dart'; import 'package:pspdfkit_flutter/src/web/pspdfkit_web_utils.dart'; -import '../document/page_info.dart'; /// This class is used to interact with a /// [PSPDFKit.Instance](https://pspdfkit.com/api/web/PSPDFKit.Instance.html) in @@ -358,16 +358,22 @@ class PspdfkitWebInstance { Future getPageInfo(int pageIndex) async { var pageInfo = _pspdfkitInstance.callMethod('pageInfoForIndex', [pageIndex]); - return PageInfo.fromJson(pageInfo); + return PageInfo( + pageIndex: pageInfo['pageIndex'], + height: pageInfo['height'], + width: pageInfo['width'], + rotation: pageInfo['rotation'], + label: pageInfo['label'], + ); } /// Exports the current document as a raw PDF file. /// The [options] parameter is an optional [DocumentSaveOptions] object that specifies the export options. /// Returns a [Future] that completes with a [Uint8List] containing the exported PDF data. Future exportPdf({DocumentSaveOptions? options}) async { - var webOptions = options?.toWebOptions(); - var arrayBuffer = await promiseToFuture(_pspdfkitInstance.callMethod( - 'exportPDF', [JsObject.jsify(webOptions ?? {})])); + var webOptions = options!.toWebOptions(); + var arrayBuffer = await promiseToFuture(_pspdfkitInstance + .callMethod('exportPDF', [JsObject.jsify(webOptions)])); var uintList = JsObject(context['Uint8Array'], [arrayBuffer]); JsArray jsArray = context['Array'].callMethod('from', [uintList]); diff --git a/lib/src/web/pspdfkit_web_utils.dart b/lib/src/web/pspdfkit_web_utils.dart index 3289861f..ee2f2121 100644 --- a/lib/src/web/pspdfkit_web_utils.dart +++ b/lib/src/web/pspdfkit_web_utils.dart @@ -101,8 +101,11 @@ PspdfkitWebToolbarItem webToolbarItemFromJsObject(JsObject jsObject) { var json = jsObject.toJson(); return PspdfkitWebToolbarItem( - type: PspdfkitWebToolbarItemType.values - .firstWhere((e) => e.name == json['type']), + type: PspdfkitWebToolbarItemType.values.firstWhere( + (e) => e.name == json['type'], + orElse: () => + // Introduction of a new toolbar item type causes a runtime error. + throw Exception('Unknown toolbar item type: ${json['type']}')), title: json['title'], className: json['className'], disabled: json['disabled'], diff --git a/lib/src/widgets/pspdfkit_flutter_widget_controller_impl.dart b/lib/src/widgets/pspdfkit_flutter_widget_controller_impl.dart new file mode 100644 index 00000000..837faecf --- /dev/null +++ b/lib/src/widgets/pspdfkit_flutter_widget_controller_impl.dart @@ -0,0 +1,142 @@ +import 'dart:convert'; + +import 'package:flutter/services.dart'; +import 'package:pspdfkit_flutter/pspdfkit.dart'; +import '../document/pdf_document_native.dart'; + +class PspdfkitFlutterWidgetControllerImpl + implements PspdfkitWidgetController, PspdfkitWidgetCallbacks { + final PspdfkitWidgetControllerApi _pspdfkitWidgetControllerApi; + final PdfDocumentLoadedCallback? onPdfDocumentLoaded; + final PdfDocumentLoadFailedCallback? onPdfDocumentLoadFailed; + final PageChangedCallback? onPdfPageChanged; + + PspdfkitFlutterWidgetControllerImpl( + this._pspdfkitWidgetControllerApi, { + this.onPdfDocumentLoaded, + this.onPdfDocumentLoadFailed, + this.onPdfPageChanged, + }); + + @override + Future addAnnotation(Map jsonAnnotation) { + return _pspdfkitWidgetControllerApi + .addAnnotation(jsonEncode(jsonAnnotation)); + } + + @override + Future addEventListener( + String eventName, Function(dynamic p1) callback) { + throw UnimplementedError(); + } + + @override + Future applyInstantJson(String annotationsJson) { + return _pspdfkitWidgetControllerApi.applyInstantJson(annotationsJson); + } + + @override + Future exportInstantJson() { + return _pspdfkitWidgetControllerApi.exportInstantJson(); + } + + @override + Future exportXfdf(String xfdfPath) { + return _pspdfkitWidgetControllerApi.exportXfdf(xfdfPath); + } + + @override + Future getAllUnsavedAnnotations() { + return _pspdfkitWidgetControllerApi.getAllUnsavedAnnotations(); + } + + @override + Future getAnnotations(int pageIndex, String type) { + return _pspdfkitWidgetControllerApi.getAnnotations(pageIndex, type); + } + + @override + Future getFormFieldValue(String fullyQualifiedName) { + return _pspdfkitWidgetControllerApi.getFormFieldValue(fullyQualifiedName); + } + + @override + Future getVisibleRect(int pageIndex) async { + PdfRect rect = await _pspdfkitWidgetControllerApi.getVisibleRect(pageIndex); + return Rect.fromLTWH(rect.x, rect.y, rect.width, rect.height); + } + + @override + Future getZoomScale(int pageIndex) { + return _pspdfkitWidgetControllerApi.getZoomScale(pageIndex); + } + + @override + Future importXfdf(String xfdfPath) { + return _pspdfkitWidgetControllerApi.importXfdf(xfdfPath); + } + + @override + Future processAnnotations(AnnotationType type, + AnnotationProcessingMode processingMode, String destinationPath) { + return _pspdfkitWidgetControllerApi.processAnnotations( + type, processingMode, destinationPath); + } + + @override + Future removeAnnotation(jsonAnnotation) { + return _pspdfkitWidgetControllerApi.removeAnnotation(jsonAnnotation); + } + + @override + Future save() { + return _pspdfkitWidgetControllerApi.save(); + } + + @override + Future setAnnotationConfigurations( + Map configurations) { + var config = configurations.map((key, value) { + return MapEntry(key.name, value.toMap()); + }); + return _pspdfkitWidgetControllerApi.setAnnotationConfigurations( + config.cast>()); + } + + @override + Future setFormFieldValue(String value, String fullyQualifiedName) { + return _pspdfkitWidgetControllerApi.setFormFieldValue( + value, fullyQualifiedName); + } + + @override + Future zoomToRect(int pageIndex, Rect rect) { + return _pspdfkitWidgetControllerApi.zoomToRect( + pageIndex, + PdfRect( + x: rect.left, y: rect.top, width: rect.width, height: rect.height), + null, + null); + } + + @override + void onDocumentError(String documentId, String error) { + onPdfDocumentLoadFailed?.call(error); + } + + @override + void onDocumentLoaded(String documentId) { + var methodChannel = MethodChannel('com.pspdfkit.document.$documentId'); + var api = PdfDocumentApi( + binaryMessenger: methodChannel.binaryMessenger, + messageChannelSuffix: documentId); + + onPdfDocumentLoaded + ?.call(PdfDocumentNative(documentId: documentId, api: api)); + } + + @override + void onPageChanged(String documentId, int pageIndex) { + onPdfPageChanged?.call(pageIndex); + } +} diff --git a/lib/src/widgets/pspdfkit_widget.dart b/lib/src/widgets/pspdfkit_widget.dart index 5e88f29f..5cf29796 100644 --- a/lib/src/widgets/pspdfkit_widget.dart +++ b/lib/src/widgets/pspdfkit_widget.dart @@ -16,6 +16,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:pspdfkit_flutter/pspdfkit.dart'; +import 'pspdfkit_flutter_widget_controller_impl.dart'; import 'pspdfkit_widget_controller_native.dart'; class PspdfkitWidget extends StatefulWidget { @@ -44,6 +45,7 @@ class PspdfkitWidget extends StatefulWidget { class _PspdfkitWidgetState extends State { late PspdfkitWidgetController controller; + late int? _id; @override Widget build(BuildContext context) { @@ -113,12 +115,39 @@ class _PspdfkitWidgetState extends State { } Future _onPlatformViewCreated(int id) async { - controller = PspdfkitWidgetControllerNative( - id, - onPageChanged: widget.onPageChanged, - onPdfDocumentLoadFailed: widget.onPdfDocumentError, - onPdfDocumentLoaded: widget.onPdfDocumentLoaded, + setState(() { + _id = id; + }); + MethodChannel channel = MethodChannel('com.pspdfkit.widget.$id'); + var api = PspdfkitWidgetControllerApi( + binaryMessenger: channel.binaryMessenger, + messageChannelSuffix: '$id', ); + controller = Pspdfkit.useLegacy + ? PspdfkitWidgetControllerNative( + channel, + onPageChanged: widget.onPageChanged, + onPdfDocumentLoadFailed: widget.onPdfDocumentError, + onPdfDocumentLoaded: widget.onPdfDocumentLoaded, + ) + : PspdfkitFlutterWidgetControllerImpl( + api, + onPdfPageChanged: widget.onPageChanged, + onPdfDocumentLoadFailed: widget.onPdfDocumentError, + onPdfDocumentLoaded: widget.onPdfDocumentLoaded, + ); widget.onPspdfkitWidgetCreated?.call(controller); + if (controller is PspdfkitFlutterWidgetControllerImpl) { + PspdfkitWidgetCallbacks.setUp( + controller as PspdfkitFlutterWidgetControllerImpl, + messageChannelSuffix: 'widget.callbacks.$id'); + } + } + + @override + void dispose() { + PspdfkitWidgetCallbacks.setUp(null, + messageChannelSuffix: 'widget.callbacks.$_id'); + super.dispose(); } } diff --git a/lib/src/widgets/pspdfkit_widget_controller.dart b/lib/src/widgets/pspdfkit_widget_controller.dart index 79efaf0a..9015c5e6 100644 --- a/lib/src/widgets/pspdfkit_widget_controller.dart +++ b/lib/src/widgets/pspdfkit_widget_controller.dart @@ -14,29 +14,37 @@ import '../../pspdfkit.dart'; /// A controller for a PSPDFKit widget. abstract class PspdfkitWidgetController { /// Sets the value of a form field by specifying its fully qualified field name. + @Deprecated('Use [PdfDocument.setFormFieldValue] instead.') Future setFormFieldValue(String value, String fullyQualifiedName); /// Gets the form field value by specifying its fully qualified name. + @Deprecated('Use [PdfDocument.getFormFieldValue] instead.') Future getFormFieldValue(String fullyQualifiedName); /// Applies Instant document JSON to the presented document. + @Deprecated('Use [PdfDocument.applyInstantJson] instead.') Future applyInstantJson(String annotationsJson); /// Exports Instant document JSON from the presented document. + @Deprecated('Use [PdfDocument.exportInstantJson] instead.') Future exportInstantJson(); /// Adds the given annotation to the presented document. /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + @Deprecated('Use [PdfDocument.addAnnotation] instead.') Future addAnnotation(Map jsonAnnotation); /// Removes the given annotation from the presented document. /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + @Deprecated('Use [PdfDocument.removeAnnotation] instead.') Future removeAnnotation(dynamic jsonAnnotation); /// Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. + @Deprecated('Use [PdfDocument.getAnnotations] instead.') Future getAnnotations(int pageIndex, String type); /// Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. + @Deprecated('Use [PdfDocument.getAllUnsavedAnnotations] instead.') Future getAllUnsavedAnnotations(); /// Processes annotations of the given type with the provided processing @@ -48,13 +56,16 @@ abstract class PspdfkitWidgetController { ); /// Imports annotations from the XFDF file at the given path. + @Deprecated('Use [PdfDocument.importXfdf] instead.') Future importXfdf(String xfdfPath); /// Exports annotations to the XFDF file at the given path. + @Deprecated('Use [PdfDocument.exportXfdf] instead.') Future exportXfdf(String xfdfPath); /// Saves the document back to its original location if it has been changed. /// If there were no changes to the document, the document file will not be modified. + @Deprecated('Use [PdfDocument.save] instead.') Future save(); /// Sets the annotation preset configurations for the given annotation tools. @@ -67,7 +78,7 @@ abstract class PspdfkitWidgetController { /// Sets the annotation preset configurations for the given annotation tools. /// @param eventName The name of the event to listen to. - void addEventListener(String eventName, Function(dynamic) callback); + Future addEventListener(String eventName, Function(dynamic) callback); /// Gets the visible rect of the given page. /// pageIndex The index of the page. This is a zero-based index. diff --git a/lib/src/widgets/pspdfkit_widget_controller_native.dart b/lib/src/widgets/pspdfkit_widget_controller_native.dart index 2e9af31c..504f423d 100644 --- a/lib/src/widgets/pspdfkit_widget_controller_native.dart +++ b/lib/src/widgets/pspdfkit_widget_controller_native.dart @@ -12,21 +12,26 @@ import '../../pspdfkit.dart'; import '../document/pdf_document_native.dart'; /// A controller for a PSPDFKit widget for native platforms that use the [MethodChannel]. +@Deprecated( + 'Please use the new [PspdfkitFlutterWidgetControllerImpl] widget API instead.') class PspdfkitWidgetControllerNative extends PspdfkitWidgetController { final MethodChannel _channel; PspdfkitWidgetControllerNative( - int id, { + this._channel, { PdfDocumentLoadedCallback? onPdfDocumentLoaded, PdfDocumentLoadFailedCallback? onPdfDocumentLoadFailed, PageChangedCallback? onPageChanged, - }) : _channel = MethodChannel('com.pspdfkit.widget.$id') { + }) { _channel.setMethodCallHandler((call) async { switch (call.method) { case 'onDocumentLoaded': var documentId = call.arguments['documentId'] as String; - onPdfDocumentLoaded?.call(PdfDocumentNative( - documentId: documentId, iosMethodChannel: _channel)); + var api = PdfDocumentApi( + binaryMessenger: _channel.binaryMessenger, + messageChannelSuffix: documentId); + onPdfDocumentLoaded + ?.call(PdfDocumentNative(documentId: documentId, api: api)); break; case 'onDocumentLoadFailed': onPdfDocumentLoadFailed?.call(call.arguments['error'] as String); @@ -117,7 +122,7 @@ class PspdfkitWidgetControllerNative extends PspdfkitWidgetController { } @override - void addEventListener(String eventName, Function(dynamic) callback) { + Future addEventListener(String eventName, Function(dynamic) callback) { throw UnimplementedError( 'addEventListener is not yet implemented on this platform'); } diff --git a/lib/src/widgets/pspdfkit_widget_controller_web.dart b/lib/src/widgets/pspdfkit_widget_controller_web.dart index 275aabe0..84dfe5a5 100644 --- a/lib/src/widgets/pspdfkit_widget_controller_web.dart +++ b/lib/src/widgets/pspdfkit_widget_controller_web.dart @@ -102,8 +102,9 @@ class PspdfkitWidgetControllerWeb extends PspdfkitWidgetController { } @override - void addEventListener(String eventName, Function(dynamic) callback) { - pspdfkitInstance.addEventListener(eventName, callback); + Future addEventListener( + String eventName, Function(dynamic) callback) async { + return pspdfkitInstance.addEventListener(eventName, callback); } @override diff --git a/lib/widgets/pspdfkit_widget.dart b/lib/widgets/pspdfkit_widget.dart deleted file mode 100644 index c69df79b..00000000 --- a/lib/widgets/pspdfkit_widget.dart +++ /dev/null @@ -1,13 +0,0 @@ -/// -/// Copyright © 2018-2023 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. -/// -/// -@Deprecated('Use `package:pspdfkit_flutter/pspdfkit.dart` instead') -export '../src/widgets/pspdfkit_widget.dart' - if (dart.library.io) '../src/widgets/pspdfkit_widget.dart' - if (dart.library.html) '../src/widgets/pspdfkit_widget_web.dart'; diff --git a/pigeons/copyright.txt b/pigeons/copyright.txt new file mode 100644 index 00000000..35b01f83 --- /dev/null +++ b/pigeons/copyright.txt @@ -0,0 +1,6 @@ +Copyright © 2024 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. diff --git a/pigeons/pigeon.sh b/pigeons/pigeon.sh new file mode 100644 index 00000000..ca686981 --- /dev/null +++ b/pigeons/pigeon.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +dart run pigeion \ No newline at end of file diff --git a/pigeons/pspdfkit.dart b/pigeons/pspdfkit.dart new file mode 100644 index 00000000..34270faf --- /dev/null +++ b/pigeons/pspdfkit.dart @@ -0,0 +1,616 @@ +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon(PigeonOptions( + dartOut: 'lib/src/api/pspdfkit_api.g.dart', + dartOptions: DartOptions(), + kotlinOut: + 'android/src/main/java/com/pspdfkit/flutter/pspdfkit/api/PspdfkitApi.g.kt', + kotlinOptions: KotlinOptions( + package: 'com.pspdfkit.flutter.pspdfkit.api', + errorClassName: 'PspdfkitApiError'), + swiftOut: 'ios/Classes/api/PspdfkitApi.g.swift', + swiftOptions: SwiftOptions( + errorClassName: 'PspdfkitApiError', + ), + copyrightHeader: 'pigeons/copyright.txt', + dartPackageName: 'pspdfkit_flutter')) +enum AndroidPermissionStatus { + notDetermined, + denied, + authorized, + deniedNeverAsk +} + +/// Represents the native annotation type. +enum AnnotationType { + all, + none, + undefined, + link, + highlight, + strikeout, + underline, + squiggly, + freeText, + ink, + square, + circle, + line, + note, + stamp, + caret, + richMedia, + screen, + widget, + file, + sound, + polygon, + polyline, + popup, + watermark, + trapNet, + type3d, + redact +} + +enum AnnotationTool { + inkPen, + inkMagic, + inkHighlighter, + freeText, + freeTextCallOut, + stamp, + image, + highlight, + underline, + squiggly, + strikeOut, + line, + arrow, + square, + circle, + polygon, + polyline, + eraser, + cloudy, + link, + caret, + richMedia, + screen, + file, + widget, + redaction, + signature, + stampImage, + note, + sound, + measurementAreaRect, + measurementAreaPolygon, + measurementAreaEllipse, + measurementPerimeter, + measurementDistance, +} + +enum AnnotationToolVariant { + inkPen, + inkMagic, + inkHighlighter, + freeText, + freeTextCallOut, + stamp, + image, + highlight, + underline, +} + +enum AnnotationProcessingMode { + flatten, + remove, + embed, + print, +} + +class PdfRect { + PdfRect({ + required this.x, + required this.y, + required this.width, + required this.height, + }); + + final double x; + final double y; + final double width; + final double height; +} + +class PageInfo { + PageInfo({ + required this.pageIndex, + required this.height, + required this.width, + required this.rotation, + this.label = '', + }); + + /// The index of the page. This is a zero-based index. + final int pageIndex; + + /// The height of the page in points. + final double height; + + /// The width of the page in points. + final double width; + + /// The rotation of the page in degrees. + final int rotation; + + /// The label of the page. + final String label; +} + +class DocumentSaveOptions { + /// The password is used to encrypt the document. On Web, it's used as the user password. + final String? userPassword; + + /// The owner password is used to encrypt the document and set permissions. It's only used on Web. + final String? ownerPassword; + + /// Flatten annotations and form fields into the page content. + final bool? flatten; + + /// Whether to save the document incrementally. + final bool? incremental; + + /// The permissions to set on the document. See [DocumentPermissions] for more information. + final List? permissions; + + /// The PDF version to save the document as. + final PdfVersion? pdfVersion; + + /// Whether to exclude annotations from the exported document. + final bool? excludeAnnotations; + + /// Whether to exclude annotations that have the noPrint flag set to true from the exported document (Standalone only) + final bool? saveForPrinting; + + /// Whether to include comments in the exported document (Server-Backed only). + final bool? includeComments; + + /// Whether tp allow you to export a PDF in PDF/A format. + final Object? outputFormat; + + /// Whether to optimize the document for the web. + final bool? optimize; + + DocumentSaveOptions( + {this.userPassword, + this.ownerPassword, + this.flatten, + this.incremental, + this.permissions, + this.pdfVersion, + this.excludeAnnotations, + this.saveForPrinting, + this.includeComments, + this.outputFormat, + this.optimize}); +} + +enum DocumentPermissions { + /// Allow printing of document. + printing, + + /// Modify the contents of the document. + modification, + + /// Copy text and images from the document. + extract, + + /// Add or modify text annotations, fill in interactive form fields. + annotationsAndForms, + + /// Fill in existing interactive form fields (including signature fields). + fillForms, + + /// Extract text and images from the document. + extractAccessibility, + + /// Assemble the document (insert, rotate, or delete pages and create document outline items or thumbnail images). + assemble, + + /// Print high quality. + printHighQuality; +} + +/// The PDF version of a document. +enum PdfVersion { + pdf_1_0, + pdf_1_1, + pdf_1_2, + pdf_1_3, + pdf_1_4, + pdf_1_5, + pdf_1_6, + pdf_1_7, +} + +enum PdfFormFieldTypes { + // Text field + text, + + // Checkbox + checkbox, + + // Radio button + radioButton, + + // Combo box + comboBox, + + // List box + listBox, + + // Signature field + signature, + + // Button + button, + + // Unknown field type + unknown +} + +class PdfFormOption { + /// The value of the option. + final String value; + + /// The label of the option. + final String label; + + PdfFormOption({required this.value, required this.label}); +} + +class FormFieldData { + final String name; + final String? alternativeFieldName; + final String? fullyQualifiedName; + final PdfFormFieldTypes type; + final Object? annotations; + final bool? isReadOnly; + final bool? isRequired; + final bool? isExported; + final bool? isDirty; + final List? options; + + FormFieldData({ + required this.name, + this.alternativeFieldName, + this.fullyQualifiedName, + required this.type, + this.annotations, + this.isReadOnly, + this.isRequired, + this.isExported, + this.isDirty, + this.options, + }); +} + +/// The API for interacting with a PDF document. +@HostApi() +abstract class PspdfkitApi { + @async + String? getFrameworkVersion(); + + @async + void setLicenseKey(String? licenseKey); + + @async + void setLicenseKeys( + String? androidLicenseKey, String? iOSLicenseKey, String? webLicenseKey); + + @async + bool? present(String document, {Map? configuration}); + + @async + bool? presentInstant(String serverUrl, String jwt, + {Map? configuration}); + + @async + bool? setFormFieldValue(String value, String fullyQualifiedName); + + @async + String? getFormFieldValue(String fullyQualifiedName); + + @async + bool? applyInstantJson(String annotationsJson); + + @async + String? exportInstantJson(); + + @async + bool? addAnnotation(String jsonAnnotation); + + @async + bool? removeAnnotation(String jsonAnnotation); + + @async + Object? getAnnotations(int pageIndex, String type); + + @async + Object? getAllUnsavedAnnotations(); + + @async + bool? processAnnotations( + AnnotationType type, + AnnotationProcessingMode processingMode, + String destinationPath, + ); + + @async + bool? importXfdf(String xfdfString); + + @async + bool? exportXfdf(String xfdfPath); + + @async + bool? save(); + + @async + bool? setDelayForSyncingLocalChanges(double delay); + + @async + bool? setListenToServerChanges(bool listen); + + @async + bool? syncAnnotations(); + + @async + bool? checkAndroidWriteExternalStoragePermission(); + + @async + AndroidPermissionStatus requestAndroidWriteExternalStoragePermission(); + + @async + void openAndroidSettings(); + + @async + bool? setAnnotationPresetConfigurations(Map configurations); + + @async + String getTemporaryDirectory(); + + @async + String getAuthorName(); + + /// Generate PDF from Images, Template, and Patterns. + ///[pages]: [NewPage]s to be added to the PDF. + ///[outputPath]: The path to the output file. + /// Returns the path to the generated PDF path or null if the input is invalid or if the PDF generation fails. + @async + String? generatePdf(List> pages, String outputPath); + + /// Generates a PDF from HTML string. + /// + /// [html]: The HTML string to be converted to PDF. + /// [outPutFile]: The path to the output file. + /// Returns the path to the generated PDF file or null if the input is invalid or if the PDF generation fails. + @async + String? generatePdfFromHtmlString( + String html, String outPutFile, Map? options); + + // /// Generates a PDF from HTML URI. + // /// [htmlUri]: The URI to the HTML file to be converted to PDF. The URI can be for a local file or a remote file. + // /// [outPutFile]: The path to the output file. + // /// Returns the path to the generated PDF file or null if the input is invalid or if the PDF generation fails. + @async + String? generatePdfFromHtmlUri( + String htmlUri, String outPutFile, Map? options); +} + +@FlutterApi() +abstract class PspdfkitFlutterApiCallbacks { + /// onPAuse callback for FlutterPdfActivity + void onPdfActivityOnPause(); + + void onPdfFragmentAdded(); + + void onDocumentLoaded(String documentId); + + /// ViewControllerWillDismiss callback for PDFViewController + void onPdfViewControllerWillDismiss(); + + /// ViewControllerDidDismiss callback for PDFViewController + void onPdfViewControllerDidDismiss(); + + /// Called when instant synchronization starts. + void onInstantSyncStarted(String documentId); + + /// Called when instant synchronization ends. + void onInstantSyncFinished(String documentId); + + /// Called when instant synchronization fails. + void onInstantSyncFailed(String documentId, String error); + + /// Called when instant authentication is done. + void onInstantAuthenticationFinished(String documentId, String validJWT); + + /// Called when instant authentication fails. + void onInstantAuthenticationFailed(String documentId, String error); + + /// Only available on iOS. + /// Called when instant document download is done. + void onInstantDownloadFinished(String documentId); + + /// Only available on iOS. + /// Called when instant document download fails. + void onInstantDownloadFailed(String documentId, String error); +} + +@HostApi() +abstract class PspdfkitWidgetControllerApi { + /// Sets the value of a form field by specifying its fully qualified field name. + /// This method is deprecated. Use [PdfDocument.setFormFieldValue] instead. + @async + bool? setFormFieldValue(String value, String fullyQualifiedName); + + /// Gets the form field value by specifying its fully qualified name. + @async + String? getFormFieldValue(String fullyQualifiedName); + + /// Applies Instant document JSON to the presented document. + @async + bool? applyInstantJson(String annotationsJson); + + /// Exports Instant document JSON from the presented document. + @async + String? exportInstantJson(); + + /// Adds the given annotation to the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + @async + bool? addAnnotation(String jsonAnnotation); + + /// Removes the given annotation from the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + @async + bool? removeAnnotation(String jsonAnnotation); + + /// Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. + @async + Object getAnnotations(int pageIndex, String type); + + /// Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. + @async + Object getAllUnsavedAnnotations(); + + /// Processes annotations of the given type with the provided processing + /// mode and stores the PDF at the given destination path. + @async + bool processAnnotations( + AnnotationType type, + AnnotationProcessingMode processingMode, + String destinationPath, + ); + + /// Imports annotations from the XFDF file at the given path. + @async + bool importXfdf(String xfdfString); + + /// Exports annotations to the XFDF file at the given path. + @async + bool exportXfdf(String xfdfPath); + + /// Saves the document back to its original location if it has been changed. + /// If there were no changes to the document, the document file will not be modified. + @async + bool save(); + + /// Sets the annotation preset configurations for the given annotation tools. + /// @param configurations A map of annotation tools and their corresponding configurations. + /// @param modifyAssociatedAnnotations Whether to modify the annotations associated with the old configuration. Only used for Android. + /// @return True if the configurations were set successfully, false otherwise. + @async + bool? setAnnotationConfigurations( + Map> configurations, + ); + + /// Gets the visible rect of the given page. + /// pageIndex The index of the page. This is a zero-based index. + /// Returns a [Future] that completes with the visible rect of the given page. + @async + PdfRect getVisibleRect(int pageIndex); + + /// Zooms to the given rect on the given page. + /// pageIndex The index of the page. This is a zero-based index. + /// rect The rect to zoom to. + /// Returns a [Future] that completes when the zoom operation is done. + @async + bool zoomToRect( + int pageIndex, PdfRect rect, bool? animated, double? duration); + + /// Gets the zoom scale of the given page. + /// pageIndex The index of the page. This is a zero-based index. + /// Returns a [Future] that completes with the zoom scale of the given page. + @async + double getZoomScale(int pageIndex); +} + +@HostApi() +abstract class PdfDocumentApi { + /// Returns the page info for the given page index. + /// pageIndex The index of the page. This is a zero-based index. + @async + PageInfo getPageInfo(int pageIndex); + + /// Exports the document as a PDF. + /// options:[DocumentSaveOptions] The options to use when exporting the document. + /// Returns a [Uint8List] containing the exported PDF data. + @async + Uint8List exportPdf(DocumentSaveOptions? options); + + // Returns the form field with the given name. + @async + Map getFormField(String fieldName); + + /// Returns a list of all form fields in the document. + @async + List> getFormFields(); + + /// Sets the value of a form field by specifying its fully qualified field name. + @async + bool? setFormFieldValue(String value, String fullyQualifiedName); + + /// Gets the form field value by specifying its fully qualified name. + @async + String? getFormFieldValue(String fullyQualifiedName); + + /// Applies Instant document JSON to the presented document. + @async + bool? applyInstantJson(String annotationsJson); + + /// Exports Instant document JSON from the presented document. + @async + String? exportInstantJson(); + + /// Adds the given annotation to the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + @async + bool? addAnnotation(String jsonAnnotation); + + /// Removes the given annotation from the presented document. + /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). + @async + bool? removeAnnotation(String jsonAnnotation); + + /// Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. + @async + Object getAnnotations(int pageIndex, String type); + + /// Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. + @async + Object getAllUnsavedAnnotations(); + + /// Imports annotations from the XFDF file at the given path. + @async + bool importXfdf(String xfdfString); + + /// Exports annotations to the XFDF file at the given path. + @async + bool exportXfdf(String xfdfPath); + + /// Saves the document back to its original location if it has been changed. + /// If there were no changes to the document, the document file will not be modified. + @async + bool save(String? outputPath, DocumentSaveOptions? options); +} + +@FlutterApi() +abstract class PspdfkitWidgetCallbacks { + void onDocumentLoaded(String documentId); + + void onDocumentError(String documentId, String error); + + void onPageChanged(String documentId, int pageIndex); +} diff --git a/protos/method_channels.proto b/protos/method_channels.proto deleted file mode 100644 index f8678e10..00000000 --- a/protos/method_channels.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto3"; - -enum MethodChannels { - document = 0; - setMeasurementConfiguration = 1; -} - -message MeasurementConfigurationRequest { - string name = 1; -} - diff --git a/pubspec.yaml b/pubspec.yaml index 2f540b37..e28595df 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: pspdfkit_flutter -description: A Flutter plugin providing a feature-rich PDF viewing and editing experience to your users with the powerful PSPDFKit PDF SDK. -version: 3.12.1 +description: A Flutter plugin providing a feature-rich PDF viewing and editing experience to your users with the powerful Nutrient PDF SDK. +version: 4.0.0 homepage: https://pspdfkit.com/ repository: https://github.com/PSPDFKit/pspdfkit-flutter issue_tracker: https://support.pspdfkit.com/hc/en-us/requests/new @@ -10,13 +10,11 @@ environment: flutter: '>=3.16.9' dependencies: - build_runner: ^2.2.1 flutter: sdk: flutter flutter_web_plugins: sdk: flutter plugin_platform_interface: ^2.0.2 - mockito: ^5.3.1 # For information on the generic Dart part of this file, see the @@ -41,3 +39,7 @@ dev_dependencies: flutter_lints: ^2.0.1 flutter_test: sdk: flutter + pigeon: ^22.4.0 + build_runner: ^2.2.1 + pigeon_build_runner: ^1.1.1 + mockito: ^5.3.1 diff --git a/screenshots/flutter.png b/screenshots/flutter.png new file mode 100644 index 00000000..fa6fb749 Binary files /dev/null and b/screenshots/flutter.png differ diff --git a/ui-tests/android-flow.yml b/ui-tests/android-flow.yml deleted file mode 100644 index a5d60191..00000000 --- a/ui-tests/android-flow.yml +++ /dev/null @@ -1,10 +0,0 @@ -# flow.yaml -appId: com.pspdfkit.flutter.example ---- -- launchApp -- tapOn: "Basic Example\nOpens a PDF Document." -- tapOn: - id: "com.pspdfkit.flutter.example:id/pspdf__menu_option_edit_annotations" -- tapOn: - id: "com.pspdfkit.flutter.example:id/pspdf__annotation_creation_toolbar_group_m\ - easurement" diff --git a/ui-tests/ios-flow.yml b/ui-tests/ios-flow.yml deleted file mode 100644 index e69de29b..00000000