From 4d53995d53aa798564227c043851374f44317167 Mon Sep 17 00:00:00 2001 From: PSPDFKit Date: Fri, 3 May 2024 18:32:27 +0300 Subject: [PATCH] Release 3.10.0 --- CHANGELOG.md | 12 ++- android/build.gradle | 5 + .../pspdfkit/FlutterPdfUiFragmentCallbacks.kt | 48 ++++++++-- .../pspdfkit/flutter/pspdfkit/PSPDFKitView.kt | 45 ++++++++- .../flutter/pspdfkit/util/ProcessorHelper.kt | 85 +++++++++++++++++ example/ios/Podfile | 4 +- example/lib/examples.dart | 8 ++ example/lib/main.dart | 1 - example/lib/pspdfkit_basic_example.dart | 4 +- example/lib/pspdfkit_document_example.dart | 84 +++++++++++++++++ example/pubspec.yaml | 2 +- ios/Classes/ExportHelper.swift | 39 ++++++++ ios/Classes/PspdfPlatformView.m | 14 ++- ios/Classes/PspdfkitFlutterHelper.m | 27 ++++++ ios/Classes/PspdfkitPlugin.m | 2 +- ios/pspdfkit_flutter.podspec | 8 +- lib/pspdfkit.dart | 4 + .../annotations/annotation_tool_variant.dart | 3 +- lib/src/document/document_permissions.dart | 32 +++++++ lib/src/document/document_save_options.dart | 91 +++++++++++++++++++ lib/src/document/page_info.dart | 56 ++++++++++++ lib/src/document/pdf_document.dart | 26 ++++++ lib/src/document/pdf_document_native.dart | 46 ++++++++++ lib/src/document/pdf_document_web.dart | 32 +++++++ lib/src/document/pdf_version.dart | 18 ++++ lib/src/measurements/measurements.dart | 2 +- lib/src/types.dart | 11 +++ lib/src/web/pspdfkit_web_instance.dart | 24 ++++- lib/src/widgets/pspdfkit_widget.dart | 16 +++- .../pspdfkit_widget_controller_native.dart | 49 +++++----- .../pspdfkit_widget_controller_web.dart | 3 +- lib/src/widgets/pspdfkit_widget_web.dart | 26 +++++- pubspec.yaml | 2 +- 33 files changed, 766 insertions(+), 63 deletions(-) create mode 100644 android/src/main/java/com/pspdfkit/flutter/pspdfkit/util/ProcessorHelper.kt create mode 100644 example/lib/pspdfkit_document_example.dart create mode 100644 ios/Classes/ExportHelper.swift create mode 100644 lib/src/document/document_permissions.dart create mode 100644 lib/src/document/document_save_options.dart create mode 100644 lib/src/document/page_info.dart create mode 100644 lib/src/document/pdf_document.dart create mode 100644 lib/src/document/pdf_document_native.dart create mode 100644 lib/src/document/pdf_document_web.dart create mode 100644 lib/src/document/pdf_version.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 77aaebbe..fa68042f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,20 @@ ## Newest Release +### 3.10.0 - 03 May 2024 +- Adds APIs to get page information such as size, rotation and label. (J#HYB-195) +- Adds document load callbacks to `PspdfkitWidget`. (J#HYB-195) +- Adds page change callback to `PspdfkitWidget`. (J#HYB-195) +- Adds support for exporting document as binary data. (J#HYB-337) +- Updates for PSPDFKit 2024.2.1 for Android. +- Updates for PSPDFKit 13.4.1 for iOS. + +## Previous Releases + ### 3.9.1 - 12 Apr 2024 - Downgrades to AGP 7.* for backward compatibility (J#HYB-290) - Allow null value for `Pspdfkit.setLicenseKey` (J#HYB-294) - Updates for PSPDFKit 2024.2.1 for Android (J#HYB-303) -## Previous Releases - ### 3.9.0 - 22 Mar 2024 - Adds annotation toolbar customization for iOS and Android. (J#HYB-209) diff --git a/android/build.gradle b/android/build.gradle index 411b7629..7bff0f83 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -61,4 +61,9 @@ dependencies { 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" } 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 1a9517be..1a09ce14 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragmentCallbacks.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragmentCallbacks.kt @@ -3,14 +3,16 @@ package com.pspdfkit.flutter.pspdfkit import android.content.Context import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager -import com.pspdfkit.annotations.measurements.MeasurementValueConfiguration import com.pspdfkit.document.PdfDocument import com.pspdfkit.flutter.pspdfkit.util.MeasurementHelper import com.pspdfkit.listeners.SimpleDocumentListener import com.pspdfkit.ui.PdfFragment +import io.flutter.plugin.common.MethodChannel + +class FlutterPdfUiFragmentCallbacks(val methodChannel: MethodChannel,val measurementConfigurations: List>?): FragmentManager.FragmentLifecycleCallbacks() { + + var pdfFragment: PdfFragment? = null -class FlutterPdfUiFragmentCallbacks(val measurementConfigurations: List>?): FragmentManager.FragmentLifecycleCallbacks() { - final override fun onFragmentAttached( fm: FragmentManager, f: Fragment, @@ -18,14 +20,42 @@ class FlutterPdfUiFragmentCallbacks(val measurementConfigurations: List? = null, - ) : PlatformView, MethodCallHandler { private var fragmentContainerView: FragmentContainerView? = FragmentContainerView(context) @@ -84,9 +91,7 @@ internal class PSPDFKitView( .build() } } - - getFragmentActivity(context).supportFragmentManager.registerFragmentLifecycleCallbacks(FlutterPdfUiFragmentCallbacks(measurementValueConfigurations), true) - + getFragmentActivity(context).supportFragmentManager.registerFragmentLifecycleCallbacks(FlutterPdfUiFragmentCallbacks(methodChannel,measurementValueConfigurations), true) getFragmentActivity(context).supportFragmentManager.registerFragmentLifecycleCallbacks( object : FragmentManager.FragmentLifecycleCallbacks() { override fun onFragmentAttached( fm: FragmentManager, @@ -131,6 +136,7 @@ internal class PSPDFKitView( fragmentContainerView = null } + @SuppressLint("CheckResult") override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { // Return if the fragment or the document // are not ready. @@ -445,6 +451,35 @@ internal class PSPDFKitView( result.error("AnnotationException", e.message, null) } } + "getPageInfo" -> { + try { + val pageIndex:Int = requireNotNull(call.argument("pageIndex")) + val pageInfo = mapOf( + "width" to document.getPageSize(pageIndex).width, + "height" to document.getPageSize(pageIndex).height, + "label" to document.getPageLabel(pageIndex,false), + "index" to pageIndex, + "rotation" to document.getPageRotation(pageIndex) + ) + result.success(pageInfo) + }catch (e:Exception){ + result.error("DocumentException",e.message,null) + } + } + "exportPdf" -> { + try { + val fileUrl = document.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) + } + } else -> result.notImplemented() } } diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/util/ProcessorHelper.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/util/ProcessorHelper.kt new file mode 100644 index 00000000..576e07b2 --- /dev/null +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/util/ProcessorHelper.kt @@ -0,0 +1,85 @@ +package com.pspdfkit.flutter.pspdfkit.util + +import com.pspdfkit.document.DocumentPermissions +import com.pspdfkit.document.DocumentSaveOptions +import com.pspdfkit.document.PdfVersion +import java.util.EnumSet + +object ProcessorHelper { + fun extractSaveOptions( options: Map): DocumentSaveOptions { + val password: String? = options["password"] as String? + val permissionsList = options["permissions"]as List??: emptyList() + val incremental = options["incremental"] as Boolean? ?: false + val pdfVersion = options["pdfVersion"] as String? + val saveOptions = DocumentSaveOptions( + password, + extractPermissions(permissionsList ), + incremental, + extractPdfVersion(pdfVersion) + ) + return saveOptions + } + + private fun extractPermissions(permissions: List): EnumSet { + val documentPermissions = EnumSet.noneOf(DocumentPermissions::class.java) + for (permission in permissions) { + when (permission) { + "printing" -> documentPermissions.add(DocumentPermissions.PRINTING) + "annotationsAndForms" -> documentPermissions.add(DocumentPermissions.ANNOTATIONS_AND_FORMS) + "extractAccessibility" -> documentPermissions.add(DocumentPermissions.EXTRACT_ACCESSIBILITY) + "fillForms" -> documentPermissions.add(DocumentPermissions.FILL_FORMS) + "extract" -> documentPermissions.add(DocumentPermissions.EXTRACT) + "assemble" -> documentPermissions.add(DocumentPermissions.ASSEMBLE) + "printHighQuality" -> documentPermissions.add(DocumentPermissions.PRINT_HIGH_QUALITY) + "modification" -> documentPermissions.add(DocumentPermissions.MODIFICATION) + } + } + return documentPermissions + } + + private fun extractPdfVersion(pdfVersion: String?): PdfVersion? { + return when (pdfVersion) { + "pdf_1_0" -> PdfVersion.PDF_1_0 + "pdf_1_1" -> PdfVersion.PDF_1_1 + "pdf_1_2" -> PdfVersion.PDF_1_2 + "pdf_1_3" -> PdfVersion.PDF_1_3 + "pdf_1_4" -> PdfVersion.PDF_1_4 + "pdf_1_5" -> PdfVersion.PDF_1_5 + "pdf_1_6" -> PdfVersion.PDF_1_6 + "pdf_1_7" -> PdfVersion.PDF_1_7 + else -> null + } + } + + fun reversePdfVersion(pdfVersion: PdfVersion): String? { + return when (pdfVersion) { + PdfVersion.PDF_1_0 -> "pdf_1_0" + PdfVersion.PDF_1_1 -> "pdf_1_1" + PdfVersion.PDF_1_2 -> "pdf_1_2" + PdfVersion.PDF_1_3 -> "pdf_1_3" + PdfVersion.PDF_1_4 -> "pdf_1_4" + PdfVersion.PDF_1_5 -> "pdf_1_5" + PdfVersion.PDF_1_6 -> "pdf_1_6" + PdfVersion.PDF_1_7 -> "pdf_1_7" + } + } + + fun reversePermissions(permissions: EnumSet): List { + val permissionsList = mutableListOf() + for (permission in permissions) { + when (permission) { + DocumentPermissions.PRINTING -> permissionsList.add("printing") + DocumentPermissions.ANNOTATIONS_AND_FORMS -> permissionsList.add("annotationsAndForms") + DocumentPermissions.EXTRACT_ACCESSIBILITY -> permissionsList.add("extractAccessibility") + DocumentPermissions.FILL_FORMS -> permissionsList.add("fillForms") + DocumentPermissions.EXTRACT -> permissionsList.add("extract") + DocumentPermissions.ASSEMBLE -> permissionsList.add("assemble") + DocumentPermissions.PRINT_HIGH_QUALITY -> permissionsList.add("printHighQuality") + DocumentPermissions.MODIFICATION -> permissionsList.add("modification") + else -> permissionsList.add("printing") + } + } + return permissionsList + } + +} \ No newline at end of file diff --git a/example/ios/Podfile b/example/ios/Podfile index eff7b051..1933fcbb 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -32,8 +32,8 @@ host_cpu = RbConfig::CONFIG["host_cpu"] target "Runner" do flutter_install_all_ios_pods __dir__ - # # PSPDFKit iOS SDK version specified by PSPDFKit Flutter Plugin. Do not remove this line. - # # Instant iOS SDK version specified by PSPDFKit Flutter Plugin. Do not remove this line. + # PSPDFKit iOS SDK version specified by PSPDFKit Flutter Plugin. Do not remove this line. + # Instant iOS SDK version specified by PSPDFKit Flutter Plugin. Do not remove this line. use_modular_headers! end diff --git a/example/lib/examples.dart b/example/lib/examples.dart index 26e3d9c3..7da91b29 100644 --- a/example/lib/examples.dart +++ b/example/lib/examples.dart @@ -15,6 +15,7 @@ import 'package:pspdfkit_example/models/papsdkit_example_item.dart'; import 'package:pspdfkit_example/pspdfkit_toolbar_customization.dart'; import 'pspdfkit_annotation_preset_customisation.dart'; +import 'pspdfkit_document_example.dart'; import 'pspdfkit_event_listeners_example.dart'; import 'utils/file_utils.dart'; import 'utils/platform_utils.dart'; @@ -67,6 +68,13 @@ List examples(BuildContext context) => [ description: 'Opens an image document.', onTap: () => showImage(context), ), + PspdfkitExampleItem( + title: 'Document Example', + description: 'Shows how to get document properties after loading.', + onTap: () async { + await extractAsset(context, _documentPath).then((value) => goTo( + PspdfkitDocumentExample(documentPath: value.path), context)); + }), PspdfkitExampleItem( title: 'Dark Theme', description: 'Opens a document in night mode with a custom dark theme.', diff --git a/example/lib/main.dart b/example/lib/main.dart index 2f8c8850..3ed6be94 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -32,7 +32,6 @@ void main() { // // To set the license key for the currently running platform, use: // Pspdfkit.setLicenseKey(null); - Pspdfkit.setLicenseKey(null); runApp(const MyApp()); } diff --git a/example/lib/pspdfkit_basic_example.dart b/example/lib/pspdfkit_basic_example.dart index ecfe5093..33d9e526 100644 --- a/example/lib/pspdfkit_basic_example.dart +++ b/example/lib/pspdfkit_basic_example.dart @@ -30,6 +30,8 @@ class PspdfkitBasicExample extends StatelessWidget { padding: PlatformUtils.isAndroid() ? const EdgeInsets.only(top: kToolbarHeight) : null, - child: PspdfkitWidget(documentPath: documentPath)))); + child: PspdfkitWidget( + documentPath: documentPath, + )))); } } diff --git a/example/lib/pspdfkit_document_example.dart b/example/lib/pspdfkit_document_example.dart new file mode 100644 index 00000000..ffb16595 --- /dev/null +++ b/example/lib/pspdfkit_document_example.dart @@ -0,0 +1,84 @@ +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'utils/platform_utils.dart'; +import 'package:pspdfkit_flutter/pspdfkit.dart'; + +class PspdfkitDocumentExample extends StatefulWidget { + final String documentPath; + + const PspdfkitDocumentExample({super.key, required this.documentPath}); + + @override + State createState() => + _PspdfkitDocumentExampleState(); +} + +class _PspdfkitDocumentExampleState extends State { + PdfDocument? _document; + + @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( + actions: [ + // Export button + IconButton( + onPressed: _document == null + ? null + : () { + _document + ?.exportPdf( + options: DocumentSaveOptions( + flatten: true, + userPassword: '12345', + ownerPassword: '12345', + excludeAnnotations: true, + permissions: [ + DocumentPermissions.printHighQuality + ], + optimize: true)) + .then((Uint8List value) async { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + 'Document exported to Uint8: ${value.length}'))); + }).catchError((error) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Error: $error'))); + }); + }, + icon: const Icon(Icons.file_download), + ), + ], + ), + + body: SafeArea( + top: false, + bottom: false, + child: Container( + padding: PlatformUtils.isAndroid() + ? const EdgeInsets.only(top: kToolbarHeight) + : null, + child: PspdfkitWidget( + documentPath: widget.documentPath, + onPdfDocumentLoaded: (PdfDocument document) async { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text('Document loaded ${document.documentId}'))); + setState(() { + _document = document; + }); + }, + onPageChanged: (pageIndex) { + _document?.getPageInfo(pageIndex).then((value) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Page changed to $value'))); + }); + }, + ))), + ); + } +} diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 7f58d032..baa1bc15 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.9.1 +version: 3.10.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/ExportHelper.swift b/ios/Classes/ExportHelper.swift new file mode 100644 index 00000000..a83a7568 --- /dev/null +++ b/ios/Classes/ExportHelper.swift @@ -0,0 +1,39 @@ +// +// ExportHelper.swift +// pspdfkit_flutter +// Created by Julius Kato on 29/04/2024. +// + +import Foundation +import PSPDFKit.PSPDFProcessor +import PSPDFKit + +@objc public class DocumentExportHelper: NSObject { + + static func extractPermissions(permissions:Array) -> Array? { + var permissionsArray = Array() + for permissionString in permissions { + switch permissionString { + case "print": + permissionsArray.append(.printing) + case "modification": + permissionsArray.append(.modification) + case "extractAccessibility": + permissionsArray.append(.extractAccessibility) + case "fillForms": + permissionsArray.append(.fillForms) + case "extract": + permissionsArray.append(.extract) + case "assemble": + permissionsArray.append(.assemble) + case "printHighResolution": + permissionsArray.append(.printHighQuality) + case "annotationsAndForms": + permissionsArray.append(.annotationsAndForms) + default: + continue + } + } + return permissionsArray + } +} diff --git a/ios/Classes/PspdfPlatformView.m b/ios/Classes/PspdfPlatformView.m index c029259a..a83e17bb 100644 --- a/ios/Classes/PspdfPlatformView.m +++ b/ios/Classes/PspdfPlatformView.m @@ -68,6 +68,7 @@ - (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId argum _pdfViewController.appearanceModeManager.appearanceMode = [PspdfkitFlutterConverter appearanceMode:configurationDictionary]; _pdfViewController.pageIndex = [PspdfkitFlutterConverter pageIndex:configurationDictionary]; _pdfViewController.delegate = self; + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(documentDidFinishRendering) name:PSPDFDocumentViewControllerDidConfigureSpreadViewNotification object:nil]; if ((id)configurationDictionary != NSNull.null) { @@ -125,10 +126,21 @@ - (void)documentDidFinishRendering { object:nil]; NSString *documentId = self.pdfViewController.document.UID; if (documentId != nil) { - [_broadcastChannel invokeMethod:@"pspdfkitDocumentLoaded" arguments:documentId]; + NSDictionary *arguments = @{ + @"documentId": documentId, + }; + [_channel invokeMethod:@"onDocumentLoaded" arguments:arguments]; } } +- (void) pdfViewController:(PSPDFViewController *)pdfController willBeginDisplayingPageView:(PSPDFPageView *)pageView forPageAtIndex:(NSInteger)pageIndex { + NSDictionary *arguments = @{ + @"pageIndex": @(pageIndex), + @"documentId": pdfController.document.UID, + }; + [_channel invokeMethod:@"onPageChanged" arguments: arguments]; +} + - (void)dealloc { [self cleanup]; } diff --git a/ios/Classes/PspdfkitFlutterHelper.m b/ios/Classes/PspdfkitFlutterHelper.m index 9eddc885..ad0f88c8 100644 --- a/ios/Classes/PspdfkitFlutterHelper.m +++ b/ios/Classes/PspdfkitFlutterHelper.m @@ -7,6 +7,8 @@ // This notice may not be removed from this file. // #import "PspdfkitFlutterHelper.h" +#include +#include #import "PspdfkitFlutterConverter.h" #import "pspdfkit_flutter-Swift.h" @@ -159,6 +161,31 @@ + (void)processMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result }else if ([@"setAnnotationPresetConfigurations" isEqualToString:call.method]) { [AnnotationsPresetConfigurations setConfigurationsWithAnnotationPreset:call.arguments[@"annotationConfigurations"]]; result(nil); + } else if ([@"getPageInfo" isEqualToString:call.method]) { + NSInteger pageIndex = [call.arguments[@"pageIndex"] integerValue]; + PSPDFPageInfo *pageInfo = [pdfViewController.document pageInfoForPageAtIndex:pageIndex]; + NSDictionary *pageInfoDictionary = @{ + @"width": @(pageInfo.size.width), + @"height": @(pageInfo.size.height), + @"rotation": @(pageInfo.savedRotation), + @"index": @(pageIndex), + @"label": @"" + }; + result(pageInfoDictionary); + } else if ([@"exportPdf" isEqualToString:call.method]) { + @try { + NSString *filePath = pdfViewController.document.fileURL.path; + NSData *data = [NSData dataWithContentsOfFile:filePath]; + const uint8_t *bytes = (const uint8_t *)[data bytes]; + NSUInteger length = [data length]; + NSMutableArray *byteArray = [NSMutableArray arrayWithCapacity:length]; + for (NSUInteger i = 0; i < length; i++) { + [byteArray addObject:@(bytes[i])]; + } + result(byteArray); + } @catch (NSException *exception) { + result([FlutterError errorWithCode:@"" message:exception.reason details:nil]); + } } else { result(FlutterMethodNotImplemented); } diff --git a/ios/Classes/PspdfkitPlugin.m b/ios/Classes/PspdfkitPlugin.m index 80420ab3..79c24869 100644 --- a/ios/Classes/PspdfkitPlugin.m +++ b/ios/Classes/PspdfkitPlugin.m @@ -129,7 +129,7 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [ PspdfkitMeasurementConvertor addMeasurementValueConfigurationWithDocument:self.pdfViewController .document configuration: measurementValue]; } } - + } else if ([@"getTemporaryDirectory" isEqualToString:call.method]) { result([self getTemporaryDirectory]); }else if ([@"setAnnotationPresetConfigurations" isEqualToString:call.method]) { diff --git a/ios/pspdfkit_flutter.podspec b/ios/pspdfkit_flutter.podspec index 53b57cf3..09d85a2b 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.9.1" + s.version = "3.10.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.3.3") - s.dependency("Instant", "13.3.3") + s.dependency("PSPDFKit", "13.4.1") + s.dependency("Instant", "13.4.1") s.swift_version = "5.0" s.platform = :ios, "15.0" - s.version = "3.9.1" + s.version = "3.10.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 7c765cd1..eed2a3e0 100644 --- a/lib/pspdfkit.dart +++ b/lib/pspdfkit.dart @@ -30,6 +30,10 @@ export 'src/widgets/pspdfkit_widget.dart' 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'; part 'src/android_permission_status.dart'; diff --git a/lib/src/annotations/annotation_tool_variant.dart b/lib/src/annotations/annotation_tool_variant.dart index c9e3dbb6..46e203df 100644 --- a/lib/src/annotations/annotation_tool_variant.dart +++ b/lib/src/annotations/annotation_tool_variant.dart @@ -8,5 +8,4 @@ enum AnnotationToolVariant { image, highlight, underline, - -} \ No newline at end of file +} diff --git a/lib/src/document/document_permissions.dart b/lib/src/document/document_permissions.dart new file mode 100644 index 00000000..e2138506 --- /dev/null +++ b/lib/src/document/document_permissions.dart @@ -0,0 +1,32 @@ +/// 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 new file mode 100644 index 00000000..3956fb50 --- /dev/null +++ b/lib/src/document/document_save_options.dart @@ -0,0 +1,91 @@ +/// 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/page_info.dart b/lib/src/document/page_info.dart new file mode 100644 index 00000000..aa732584 --- /dev/null +++ b/lib/src/document/page_info.dart @@ -0,0 +1,56 @@ +/// 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 new file mode 100644 index 00000000..1c386bf4 --- /dev/null +++ b/lib/src/document/pdf_document.dart @@ -0,0 +1,26 @@ +/// 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 'dart:typed_data'; + +import 'package:pspdfkit_flutter/src/document/document_save_options.dart'; +import 'package:pspdfkit_flutter/src/document/page_info.dart'; + +abstract class PdfDocument { + final String documentId; + + PdfDocument({required this.documentId}); + + /// 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); + + /// 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}); +} diff --git a/lib/src/document/pdf_document_native.dart b/lib/src/document/pdf_document_native.dart new file mode 100644 index 00000000..f8fc8348 --- /dev/null +++ b/lib/src/document/pdf_document_native.dart @@ -0,0 +1,46 @@ +/// 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:flutter/services.dart'; +import 'package:pspdfkit_flutter/src/document/page_info.dart'; + +import 'document_save_options.dart'; +import 'pdf_document.dart'; + +class PdfDocumentNative extends PdfDocument { + final MethodChannel _channel; + + PdfDocumentNative({required MethodChannel channel, required super.documentId}) + : _channel = channel; + + @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'); + }); + + @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'); + }); + } +} diff --git a/lib/src/document/pdf_document_web.dart b/lib/src/document/pdf_document_web.dart new file mode 100644 index 00000000..5f2651b6 --- /dev/null +++ b/lib/src/document/pdf_document_web.dart @@ -0,0 +1,32 @@ +/// 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 'dart:typed_data'; + +import 'package:pspdfkit_flutter/src/document/page_info.dart'; +import 'package:pspdfkit_flutter/src/web/pspdfkit_web_instance.dart'; + +import 'document_save_options.dart'; +import 'pdf_document.dart'; + +class PdfDocumentWeb extends PdfDocument { + final PspdfkitWebInstance _instance; + + PdfDocumentWeb( + {required super.documentId, required PspdfkitWebInstance instance}) + : _instance = instance; + + @override + Future getPageInfo(int pageIndex) { + return _instance.getPageInfo(pageIndex); + } + + @override + Future exportPdf({DocumentSaveOptions? options}) { + return _instance.exportPdf(options: options); + } +} diff --git a/lib/src/document/pdf_version.dart b/lib/src/document/pdf_version.dart new file mode 100644 index 00000000..1dea7d7f --- /dev/null +++ b/lib/src/document/pdf_version.dart @@ -0,0 +1,18 @@ +/// 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/measurements/measurements.dart b/lib/src/measurements/measurements.dart index 36067e69..30f737de 100644 --- a/lib/src/measurements/measurements.dart +++ b/lib/src/measurements/measurements.dart @@ -1,3 +1,3 @@ export 'measurement_precision.dart'; export 'measurement_scale.dart'; -export 'measurement_value_configuration.dart'; \ No newline at end of file +export 'measurement_value_configuration.dart'; diff --git a/lib/src/types.dart b/lib/src/types.dart index 47aa7b95..9e9ce33d 100644 --- a/lib/src/types.dart +++ b/lib/src/types.dart @@ -1,3 +1,5 @@ +import '../pspdfkit.dart'; + /// Copyright © 2023 PSPDFKit GmbH. All rights reserved. /// /// THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW @@ -243,6 +245,15 @@ enum ShowSignatureValidationStatusMode { never } +typedef PspdfkitWidgetCreatedCallback = void Function( + PspdfkitWidgetController view); + +typedef PdfDocumentLoadedCallback = void Function(PdfDocument document); + +typedef PdfDocumentLoadFailedCallback = void Function(String error); + +typedef PageChangedCallback = void Function(int pageIndex); + extension WebShowSignatureValidationStatusMode on ShowSignatureValidationStatusMode { String? get webName { diff --git a/lib/src/web/pspdfkit_web_instance.dart b/lib/src/web/pspdfkit_web_instance.dart index 9fd84298..9260fc98 100644 --- a/lib/src/web/pspdfkit_web_instance.dart +++ b/lib/src/web/pspdfkit_web_instance.dart @@ -1,5 +1,5 @@ /// -/// Copyright © 2023 PSPDFKit GmbH. All rights reserved. +/// Copyright © 2023-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,12 +7,17 @@ /// This notice may not be removed from this file. /// +import 'dart:async'; import 'dart:convert'; import 'dart:html'; import 'dart:js'; +import 'dart:typed_data'; import 'package:pspdfkit_flutter/pspdfkit.dart'; +import 'package:pspdfkit_flutter/src/document/page_info.dart'; import 'package:pspdfkit_flutter/src/web/pspdfkit_web_utils.dart'; +import '../document/document_save_options.dart'; + /// This class is used to interact with a /// [PSPDFKit.Instance](https://pspdfkit.com/api/web/PSPDFKit.Instance.html) in /// PSPDFKit Web SDK. @@ -347,4 +352,21 @@ class PspdfkitWebInstance { var jsItems = items.map((e) => e.toJsObject()).toList(); _pspdfkitInstance.callMethod('setToolbarItems', [JsObject.jsify(jsItems)]); } + + Future getPageInfo(int pageIndex) async { + var pageInfo = + _pspdfkitInstance.callMethod('pageInfoForIndex', [pageIndex]); + return PageInfo.fromJson(pageInfo); + } + + Future exportPdf({DocumentSaveOptions? options}) async { + 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]); + Uint8List bytes = Uint8List.fromList(List.from(jsArray)); + return bytes; + } } diff --git a/lib/src/widgets/pspdfkit_widget.dart b/lib/src/widgets/pspdfkit_widget.dart index e5b164ab..5e88f29f 100644 --- a/lib/src/widgets/pspdfkit_widget.dart +++ b/lib/src/widgets/pspdfkit_widget.dart @@ -18,19 +18,22 @@ import 'package:flutter/material.dart'; import 'package:pspdfkit_flutter/pspdfkit.dart'; import 'pspdfkit_widget_controller_native.dart'; -typedef PspdfkitWidgetCreatedCallback = void Function( - PspdfkitWidgetController view); - class PspdfkitWidget extends StatefulWidget { final String documentPath; final dynamic configuration; final PspdfkitWidgetCreatedCallback? onPspdfkitWidgetCreated; + final PdfDocumentLoadedCallback? onPdfDocumentLoaded; + final PdfDocumentLoadFailedCallback? onPdfDocumentError; + final PageChangedCallback? onPageChanged; const PspdfkitWidget({ Key? key, required this.documentPath, this.configuration, this.onPspdfkitWidgetCreated, + this.onPdfDocumentLoaded, + this.onPdfDocumentError, + this.onPageChanged, }) : super(key: key); @override @@ -110,7 +113,12 @@ class _PspdfkitWidgetState extends State { } Future _onPlatformViewCreated(int id) async { - controller = PspdfkitWidgetControllerNative(id); + controller = PspdfkitWidgetControllerNative( + id, + onPageChanged: widget.onPageChanged, + onPdfDocumentLoadFailed: widget.onPdfDocumentError, + onPdfDocumentLoaded: widget.onPdfDocumentLoaded, + ); widget.onPspdfkitWidgetCreated?.call(controller); } } diff --git a/lib/src/widgets/pspdfkit_widget_controller_native.dart b/lib/src/widgets/pspdfkit_widget_controller_native.dart index 9180200c..7e1b3e0c 100644 --- a/lib/src/widgets/pspdfkit_widget_controller_native.dart +++ b/lib/src/widgets/pspdfkit_widget_controller_native.dart @@ -9,13 +9,37 @@ import 'package:flutter/services.dart'; import '../../pspdfkit.dart'; +import '../document/pdf_document_native.dart'; /// A controller for a PSPDFKit widget for native platforms that use the [MethodChannel]. -class PspdfkitWidgetControllerNative implements PspdfkitWidgetController { +class PspdfkitWidgetControllerNative extends PspdfkitWidgetController { final MethodChannel _channel; - PspdfkitWidgetControllerNative(int id) - : _channel = MethodChannel('com.pspdfkit.widget.$id'); + PspdfkitWidgetControllerNative( + int id, { + 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, + channel: _channel, + )); + break; + case 'onDocumentLoadFailed': + onPdfDocumentLoadFailed?.call(call.arguments['error'] as String); + break; + case 'onPageChanged': + var pageIndex = call.arguments['pageIndex']; + onPageChanged?.call(pageIndex); + break; + } + }); + } @override Future setFormFieldValue( @@ -96,23 +120,4 @@ class PspdfkitWidgetControllerNative implements PspdfkitWidgetController { throw UnimplementedError( 'addEventListener is not yet implemented on this platform'); } - - List _parseMeasurementValueConfigurations( - List configurations) { - return configurations.map((e) { - var map = {}; - e.forEach((key, value) { - if (key as String == 'scale') { - var scaleMap = {}; - value.forEach((key, value) { - scaleMap[key as String] = value as dynamic; - }); - map[key] = scaleMap; - } else { - map[key] = value as dynamic; - } - }); - return MeasurementValueConfiguration.fromMap(map); - }).toList(); - } } diff --git a/lib/src/widgets/pspdfkit_widget_controller_web.dart b/lib/src/widgets/pspdfkit_widget_controller_web.dart index df1667b4..680de9cc 100644 --- a/lib/src/widgets/pspdfkit_widget_controller_web.dart +++ b/lib/src/widgets/pspdfkit_widget_controller_web.dart @@ -5,13 +5,14 @@ /// 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/web/pspdfkit_web_instance.dart'; import '../../pspdfkit.dart'; import '../web/pspdfkit_web.dart'; /// A controller for a PSPDFKit widget for Web. -class PspdfkitWidgetControllerWeb implements PspdfkitWidgetController { +class PspdfkitWidgetControllerWeb extends PspdfkitWidgetController { final PspdfkitWebInstance pspdfkitInstance; PspdfkitWidgetControllerWeb(this.pspdfkitInstance); diff --git a/lib/src/widgets/pspdfkit_widget_web.dart b/lib/src/widgets/pspdfkit_widget_web.dart index 1fca4e1b..ff095d94 100644 --- a/lib/src/widgets/pspdfkit_widget_web.dart +++ b/lib/src/widgets/pspdfkit_widget_web.dart @@ -14,22 +14,27 @@ import 'dart:ui_web' as ui; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:pspdfkit_flutter/pspdfkit.dart'; +import 'package:pspdfkit_flutter/src/web/pspdfkit_web_instance.dart'; +import '../document/pdf_document_web.dart'; import '../web/pspdfkit_web.dart'; import 'pspdfkit_widget_controller_web.dart'; -typedef PspdfkitWidgetCreatedCallback = void Function( - PspdfkitWidgetController view); - class PspdfkitWidget extends StatefulWidget { final String documentPath; final dynamic configuration; final PspdfkitWidgetCreatedCallback? onPspdfkitWidgetCreated; + final PdfDocumentLoadedCallback? onPdfDocumentLoaded; + final PdfDocumentLoadFailedCallback? onPdfDocumentLoadFailure; + final PageChangedCallback? onPageChanged; const PspdfkitWidget({ Key? key, required this.documentPath, this.configuration, this.onPspdfkitWidgetCreated, + this.onPdfDocumentLoaded, + this.onPdfDocumentLoadFailure, + this.onPageChanged, }) : super(key: key); @override @@ -80,11 +85,24 @@ class _PspdfkitWidgetState extends State { Future.delayed(const Duration(milliseconds: 10), () async { await PSPDFKitWeb.load(widget.documentPath, id, configuration) .then((value) { - var controller = PspdfkitWidgetControllerWeb(value); + _addDefaultEventListeners(value); + var controller = PspdfkitWidgetControllerWeb( + value, + ); widget.onPspdfkitWidgetCreated?.call(controller); + widget.onPdfDocumentLoaded + ?.call(PdfDocumentWeb(documentId: '', instance: value)); }).catchError((error) { + widget.onPdfDocumentLoadFailure?.call(error.toString()); throw Exception('Failed to load: $error'); }); }); } + + void _addDefaultEventListeners(PspdfkitWebInstance webInstance) { + webInstance.addEventListener('viewState.currentPageIndex.change', + (pageIndex) { + widget.onPageChanged?.call(pageIndex); + }); + } } diff --git a/pubspec.yaml b/pubspec.yaml index aba7ad58..65955751 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.9.1 +version: 3.10.0 homepage: https://pspdfkit.com/ repository: https://github.com/PSPDFKit/pspdfkit-flutter issue_tracker: https://support.pspdfkit.com/hc/en-us/requests/new