diff --git a/README.md b/README.md index d1392d0..3d5acc3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # PDFTron Flutter Sample -Flutter sample project that integrates a document viewer using [PDFTron Flutter](https://github.com/PDFTron/pdftron-flutter). Check out the [integration guides](https://www.pdftron.com/documentation/android/flutter) to learn how to add PDFTron to your Flutter App. +A Flutter sample project that integrates a document viewer using PDFTron Flutter. + +PDFTron's Flutter PDF library now supports sound null safety and is available on [GitHub](https://github.com/PDFTron/pdftron-flutter) and [pub.dev](https://pub.dev/packages/pdftron_flutter). To learn how to add PDFTron to your Flutter App, check out the [integration guides](https://www.pdftron.com/documentation/guides/flutter). ## Preview @@ -7,15 +9,17 @@ Flutter sample project that integrates a document viewer using [PDFTron Flutter] :--:|:--: demo-android | demo-android -## Step +## Installation +### Android 1. Create a `local.properties` file inside the android folder with your Android SDK location, for example: ``` sdk.dir=/Users//Library/Android/sdk ``` -2. For iOS, run: +### iOS +1. For iOS, run: ``` cd ios pod install @@ -23,13 +27,21 @@ pod install ## Run +### Sample App + ``` flutter run ``` +### Test + +``` +flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart +``` + ## Upgrade -For updating flutter projects, please check out [here](https://flutter.dev/docs/development/tools/sdk/upgrading). +For updating flutter projects, please check out [Upgrading Flutter](https://flutter.dev/docs/development/tools/sdk/upgrading). ## License See [License](./LICENSE) diff --git a/integration_test/app_test.dart b/integration_test/app_test.dart index 1b51b34..726af47 100644 --- a/integration_test/app_test.dart +++ b/integration_test/app_test.dart @@ -1,36 +1,91 @@ -// This is a basic Flutter integration test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - +import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_sample/thumbnail.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; - import 'package:flutter_sample/main.dart' as app; +import 'package:pdftron_flutter/pdftron_flutter.dart'; + +// Test for the sample app. +void main() async { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + List calls = []; + + setUpAll(() async { + // Used to track method calls. + MethodChannel('pdftron_flutter').setMockMethodCallHandler( (MethodCall call) async { + calls.add(call.method); + }); + }); + + tearDown(() { + // Clears list after each test. + calls.clear(); + }); + + // Destroys the method call tracker after all tests have ran. + tearDownAll(() async { + MethodChannel('pdftron_flutter').setMockMethodCallHandler(null); + }); + + testWidgets('Check widget hierarchy of app', (WidgetTester tester) async { + Widget myApp = app.MyApp(); + await tester.pumpWidget(myApp); -void main() => run(_testMain); + expect(find.text("PDFTron Flutter Sample"), findsOneWidget); + + final bodyFinder = find.byKey(Key('body')); + expect(bodyFinder, findsOneWidget); + + // Body widget is SafeArea type if app is initialized and storage is permitted. + final body = tester.firstWidget(bodyFinder); + if (body is SafeArea) { + final inkWellFinder = find.descendant(of: bodyFinder, matching: find.byType(InkWell)); + expect(inkWellFinder, findsWidgets); -void _testMain() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - app.main(); + final imageFinder = find.descendant(of: inkWellFinder.first, matching: find.byType(Image)); + expect(imageFinder, findsOneWidget); - // Trigger a frame. - await tester.pumpAndSettle(); + } else { + // Body widget is Container type if app is not initialized or storage is not permitted. + expect(body.runtimeType, Container); + + final alignFinder = find.descendant(of: bodyFinder, matching: find.byType(Align)); + expect(alignFinder, findsOneWidget); - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); + final textFinder = find.descendant(of: alignFinder, matching: find.byType(Text)); + expect(textFinder, findsOneWidget); - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); + Text text = tester.firstWidget(textFinder); + assert(text.data == 'Storage permission required.' || text.data == 'PDFTron SDK not initialized.'); - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); + expect(find.byType(Text), findsNWidgets(2)); + } }); + + testWidgets("Opening Thumbnail", (WidgetTester tester) async { + await tester.runAsync(() async { + await tester.pumpWidget(app.MyApp()); + await tester.pump(); + expect(find.byType(InkWell), findsWidgets); + + // Chooses a random thumbnail to select. + Random rng = Random(); + + // 6 is used instead of thumbnailList.length as that is the number of thumbnails visible upon loading. + int index = rng.nextInt(6); + Finder thumbnail = find.byKey(ValueKey(thumbnailList[index].documentUrl)); + + // Opens the selected thumbnail. + await tester.tap(thumbnail); + await tester.pump(); + + // Tests to ensure that the PdftronFlutter method were called. + await Future.delayed(Duration(seconds: 2), () async { + expect(calls.contains(Functions.openDocument), true); + }); + }); + }, variant: TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS})); } + diff --git a/integration_test/driver.dart b/integration_test/driver.dart deleted file mode 100644 index a03bca0..0000000 --- a/integration_test/driver.dart +++ /dev/null @@ -1,8 +0,0 @@ -// This file is provided as a convenience for running integration tests via the -// flutter drive command. -// -// flutter drive --driver integration_test/driver.dart --target integration_test/app_test.dart - -import 'package:integration_test/integration_test_driver.dart'; - -Future main() => integrationDriver(); diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4a6af23..e911450 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2,11 +2,11 @@ PODS: - Flutter (1.0.0) - integration_test (0.0.1): - Flutter - - PDFNet (8.1.0.76833) + - PDFNet (9.0.1.77780) - pdftron_flutter (0.0.1): - Flutter - PDFNet - - permission_handler (3.0.1): + - "permission_handler (5.1.0+2)": - Flutter DEPENDENCIES: @@ -31,10 +31,10 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c integration_test: 6eb66a19f7104200dcfdd62bc0077e1b09686e4f - PDFNet: 248e57518524fdbb47970216c2db3522e4f51028 + PDFNet: b9e7a7831af4020a4835e19ecf6abf9b81ce29a4 pdftron_flutter: 32bd96e9bc9254c1861f17725e40dd611a7056cd - permission_handler: 6e56ded745f5a0b9dcc0327c65c4acd6a33b776b + permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0 -PODFILE CHECKSUM: c3dd2ce4973c59b1eed0b8fefd9e24700fcd3376 +PODFILE CHECKSUM: 1256ed743e0e6641e71d5339a76d03b9e411be9b -COCOAPODS: 1.9.3 +COCOAPODS: 1.10.1 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 82b64c0..e9b7555 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -9,7 +9,7 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 7D9D4596AFE603889D0C4AF9 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 156D97EE3B349FF3B0506A4B /* Pods_Runner.framework */; }; + 943B166731AF29A54E1E56A7 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 204000B1A7320C6A866AAD69 /* Pods_Runner.framework */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -33,22 +33,22 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 156D97EE3B349FF3B0506A4B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 26A290795C8B345E7B54F3D8 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 204000B1A7320C6A866AAD69 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 2BE6492F675995FD34402DF3 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3BDFDD4EE7D4A48E6F1023CD /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 8C7015EC7AC266049F570AC8 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 978AC9E7D689FE7A1CC725C4 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A318E888EA367D38A42C1330 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -56,21 +56,32 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7D9D4596AFE603889D0C4AF9 /* Pods_Runner.framework in Frameworks */, + 943B166731AF29A54E1E56A7 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 526543B57B076E700259821D /* Frameworks */ = { + 144481D43B8FD6BABC279BD2 /* Frameworks */ = { isa = PBXGroup; children = ( - 156D97EE3B349FF3B0506A4B /* Pods_Runner.framework */, + 204000B1A7320C6A866AAD69 /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; }; + 68FFF092814E7FD8BDE5D113 /* Pods */ = { + isa = PBXGroup; + children = ( + 2BE6492F675995FD34402DF3 /* Pods-Runner.debug.xcconfig */, + 8C7015EC7AC266049F570AC8 /* Pods-Runner.release.xcconfig */, + A318E888EA367D38A42C1330 /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -88,8 +99,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - B73FC6430D1564515ACDA0A8 /* Pods */, - 526543B57B076E700259821D /* Frameworks */, + 68FFF092814E7FD8BDE5D113 /* Pods */, + 144481D43B8FD6BABC279BD2 /* Frameworks */, ); sourceTree = ""; }; @@ -125,17 +136,6 @@ name = "Supporting Files"; sourceTree = ""; }; - B73FC6430D1564515ACDA0A8 /* Pods */ = { - isa = PBXGroup; - children = ( - 978AC9E7D689FE7A1CC725C4 /* Pods-Runner.debug.xcconfig */, - 3BDFDD4EE7D4A48E6F1023CD /* Pods-Runner.release.xcconfig */, - 26A290795C8B345E7B54F3D8 /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -143,15 +143,15 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 828B385D0F4ED6C1571E5C5F /* [CP] Check Pods Manifest.lock */, + 428ABE4C58A2A019489A3B39 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 9F87D447099B0ED1C64C936E /* [CP] Embed Pods Frameworks */, - 69F2FFE7873B2C24CBEDA23A /* [CP] Copy Pods Resources */, + FB76715B0EFF3C89AFE1FCBA /* [CP] Embed Pods Frameworks */, + 4243294FAA000FD34AB76E5C /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -223,25 +223,24 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 69F2FFE7873B2C24CBEDA23A /* [CP] Copy Pods Resources */ = { + 4243294FAA000FD34AB76E5C /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", - "${PODS_ROOT}/PDFNet/Tools-Localization", + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Copy Pods Resources"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Tools-Localization", + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 828B385D0F4ED6C1571E5C5F /* [CP] Check Pods Manifest.lock */ = { + 428ABE4C58A2A019489A3B39 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -277,24 +276,17 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - 9F87D447099B0ED1C64C936E /* [CP] Embed Pods Frameworks */ = { + FB76715B0EFF3C89AFE1FCBA /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${PODS_ROOT}/PDFNet/PDFNet.framework", - "${PODS_ROOT}/PDFNet/Tools.framework", - "${BUILT_PRODUCTS_DIR}/integration_test/integration_test.framework", - "${BUILT_PRODUCTS_DIR}/pdftron_flutter/pdftron_flutter.framework", + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PDFNet.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Tools.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/integration_test.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/pdftron_flutter.framework", + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a1..919434a 100644 --- a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/lib/main.dart b/lib/main.dart index 3d5fcbc..da2b6f9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_sample/thumbnail.dart'; import 'package:pdftron_flutter/pdftron_flutter.dart'; -import 'package:permission_handler/permission_handler.dart'; void main() => runApp(MyApp()); @@ -15,8 +14,8 @@ const MARGIN = 5.0; const PORTRAIT_NUM_COLUMNS = 2; const LANDSCAPE_NUM_COLUMNS = 3; -final navigationColor = Platform.isIOS ? Color(0xffffffff) : Color(0xff48a1e0); -final titleColor = Platform.isIOS ? Color(0xff007aff) : Color(0xffffffff); +final navigationColor = (BuildContext context) => Theme.of(context).platform == TargetPlatform.iOS ? Color(0xffffffff) : Color(0xff48a1e0); +final titleColor = (BuildContext context) => Theme.of(context).platform == TargetPlatform.iOS ? Color(0xff007aff) : Color(0xffffffff); class MyApp extends StatefulWidget { @override @@ -24,17 +23,12 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - bool _storagePermitted = Platform.isIOS; bool _initialized = false; @override void initState() { super.initState(); initPlatformState(); - - if (Platform.isAndroid) { - askForPermission(); - } } // Platform messages are asynchronous, so we initialize in an async method. @@ -52,29 +46,15 @@ class _MyAppState extends State { } } - Future askForPermission() async { - Map permissions = - await PermissionHandler().requestPermissions([PermissionGroup.storage]); - if (granted(permissions[PermissionGroup.storage]) && mounted) { - setState(() { - _storagePermitted = true; - }); - } - } - - bool granted(PermissionStatus status) { - return status == PermissionStatus.granted; - } - - void openDocument(String document) { + void openDocument(String document) async { // configure the viewer by setting the config fields Config config = new Config(); PdftronFlutter.openDocument(document, config: config); } Widget getBody() { - if (_initialized && _storagePermitted) { - return SafeArea(child: Container( + if (_initialized) { + return SafeArea(key: Key('body'), child: Container( child: OrientationBuilder(builder: (context, orientation) { return GridView.builder( itemCount: thumbnailList.length, @@ -88,6 +68,7 @@ class _MyAppState extends State { itemBuilder: (BuildContext context, int index) { Thumbnail thumbnail = thumbnailList[index]; return InkWell( + key: ValueKey(thumbnail.documentUrl), child: Container( margin: EdgeInsets.all(MARGIN), decoration: BoxDecoration( @@ -116,12 +97,11 @@ class _MyAppState extends State { )); } else { return Container( + key: Key('body'), child: Align( alignment: Alignment .center, // Align however you like (i.e .centerRight, centerLeft) - child: Text(_initialized - ? 'Storage permission required.' - : 'PDFTron SDK not initialized.'), + child: Text('PDFTron SDK not initialized.'), )); } } @@ -134,9 +114,9 @@ class _MyAppState extends State { centerTitle: true, title: Text( 'PDFTron Flutter Sample', - style: TextStyle(color: titleColor), + style: TextStyle(color: titleColor(context)), ), - backgroundColor: navigationColor, + backgroundColor: navigationColor(context), ), body: getBody()), ); diff --git a/pubspec.lock b/pubspec.lock index 41932b8..490f2ca 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,126 +7,126 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "12.0.0" + version: "22.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "0.40.6" + version: "1.7.1" archive: dependency: transitive description: name: archive url: "https://pub.dartlang.org" source: hosted - version: "2.0.13" + version: "3.1.2" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "1.6.0" + version: "2.1.1" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.3" + version: "2.6.1" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.5" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" cli_util: dependency: transitive description: name: cli_util url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "0.3.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.5" + version: "1.15.0" convert: dependency: transitive description: name: convert url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "3.0.0" coverage: dependency: transitive description: name: coverage url: "https://pub.dartlang.org" source: hosted - version: "0.14.2" + version: "1.0.3" crypto: dependency: transitive description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "3.0.1" cupertino_icons: dependency: "direct main" description: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.3" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "6.0.0-nullsafety.4" + version: "6.1.0" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" flutter_driver: - dependency: transitive + dependency: "direct dev" description: flutter source: sdk version: "0.0.0" @@ -146,133 +146,159 @@ packages: name: glob url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "2.0.1" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" integration_test: dependency: "direct dev" description: flutter source: sdk - version: "0.9.2+2" + version: "0.0.0" io: dependency: transitive description: name: io url: "https://pub.dartlang.org" source: hosted - version: "0.3.4" + version: "1.0.0" js: dependency: transitive description: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.3-nullsafety.3" - json_rpc_2: - dependency: transitive - description: - name: json_rpc_2 - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.2" + version: "0.6.3" logging: dependency: transitive description: name: logging url: "https://pub.dartlang.org" source: hosted - version: "0.11.4" + version: "1.0.1" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.3" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.6" - node_interop: + version: "1.3.0" + mime: dependency: transitive description: - name: node_interop + name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" - node_io: + version: "1.0.0" + node_preamble: dependency: transitive description: - name: node_io + name: node_preamble url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "2.0.1" package_config: dependency: transitive description: name: package_config url: "https://pub.dartlang.org" source: hosted - version: "1.9.3" + version: "2.0.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.3" + version: "1.8.0" pdftron_flutter: dependency: "direct main" description: - path: "." - ref: HEAD - resolved-ref: "0513833f3c555a0806992cff025ce86c509551d1" - url: "git://github.com/PDFTron/pdftron-flutter.git" - source: git - version: "0.0.9" + name: pdftron_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0-beta.2" pedantic: dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.3" - permission_handler: - dependency: "direct main" - description: - name: permission_handler - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" + version: "1.11.1" platform: dependency: transitive description: name: platform url: "https://pub.dartlang.org" source: hosted - version: "3.0.0-nullsafety.4" + version: "3.0.0" pool: dependency: transitive description: name: pool url: "https://pub.dartlang.org" source: hosted - version: "1.5.0-nullsafety.3" + version: "1.5.0" process: dependency: transitive description: name: process url: "https://pub.dartlang.org" source: hosted - version: "4.0.0-nullsafety.4" + version: "4.2.1" pub_semver: dependency: transitive description: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "1.4.4" + version: "2.0.0" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.4" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + shelf_static: + dependency: transitive + description: + name: shelf_static + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" sky_engine: dependency: transitive description: flutter @@ -284,118 +310,133 @@ packages: name: source_map_stack_trace url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.4" + version: "2.1.0" source_maps: dependency: transitive description: name: source_maps url: "https://pub.dartlang.org" source: hosted - version: "0.10.10-nullsafety.3" + version: "0.10.10" source_span: dependency: transitive description: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.4" + version: "1.8.1" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.6" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" sync_http: dependency: transitive description: name: sync_http url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "0.3.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" + test: + dependency: "direct dev" + description: + name: test + url: "https://pub.dartlang.org" + source: hosted + version: "1.16.8" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.6" + version: "0.3.0" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.3.12-nullsafety.9" + version: "0.3.19" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.5" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.5" + version: "2.1.0" vm_service: dependency: transitive description: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "5.5.0" + version: "6.2.0" watcher: dependency: transitive description: name: watcher url: "https://pub.dartlang.org" source: hosted - version: "0.9.7+15" + version: "1.0.0" web_socket_channel: dependency: transitive description: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "2.1.0" webdriver: dependency: transitive description: name: webdriver url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "3.0.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" yaml: dependency: transitive description: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "3.1.0" sdks: - dart: ">=2.12.0-0.0 <3.0.0" + dart: ">=2.12.0 <3.0.0" + flutter: ">=1.12.0" diff --git a/pubspec.yaml b/pubspec.yaml index ee52404..922beb4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,27 +18,26 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: flutter: sdk: flutter - pdftron_flutter: - git: - url: git://github.com/PDFTron/pdftron-flutter.git - - permission_handler: '3.0.1' + pdftron_flutter: '1.0.0-beta.2' # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 + cupertino_icons: ^1.0.3 dev_dependencies: flutter_test: sdk: flutter integration_test: sdk: flutter + flutter_driver: + sdk: flutter + test: any # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index ae07987..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:flutter_sample/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/test_driver/integration_test.dart b/test_driver/integration_test.dart new file mode 100644 index 0000000..ad98ece --- /dev/null +++ b/test_driver/integration_test.dart @@ -0,0 +1,20 @@ +import 'dart:io' show Platform, Process; +import 'package:integration_test/integration_test_driver.dart'; +import 'package:path/path.dart'; + +// Driver for the integration test. +Future main() async { + // Obtains storage permission on Android. + Map vars = Platform.environment; + String path = join(vars['ANDROID_SDK_ROOT'] ?? vars['ANDROID_HOME'] as String, "platform-tools", Platform.isWindows ? "adb.exe" : "adb"); + await Process.run(path, [ + 'shell', + 'pm', + 'grant', + 'com.example.fluttersample', + 'android.permission.WRITE_EXTERNAL_STORAGE' + ]); + + // Starts the driver. + await integrationDriver(); +}