diff --git a/.github/workflows/publish_pub.yml b/.github/workflows/publish_pub.yml new file mode 100644 index 00000000..49446172 --- /dev/null +++ b/.github/workflows/publish_pub.yml @@ -0,0 +1,26 @@ +name: Publish to pub.dev +on: + push: + branches: + - master +jobs: + build: + runs-on: ubuntu-latest + container: + image: google/dart:latest + steps: + - uses: actions/checkout@v1 + - name: Setup credentials + run: | + mkdir -p ~/.pub-cache + cat < ~/.pub-cache/credentials.json + { + "accessToken":"${{ secrets.OAUTH_ACCESS_TOKEN }}", + "refreshToken":"${{ secrets.OAUTH_REFRESH_TOKEN }}", + "tokenEndpoint":"https://accounts.google.com/o/oauth2/token", + "scopes": [ "openid", "https://www.googleapis.com/auth/userinfo.email" ], + "expiration": 1584628470088 + } + EOF + - name: Publish package + run: pub publish -f diff --git a/.gitignore b/.gitignore index e9dc58d3..f226b14a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ .pub/ build/ +example/ios/Flutter/flutter_export_environment.sh +example/.flutter-plugins-dependencies +android/.idea/ diff --git a/CHANGELOG.md b/CHANGELOG.md index f3b834e0..c9b0c734 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,43 +1,22 @@ -## 1.0.7 +# Changelog -- Updated project to meet changed requirements by Flutter -- Updated third-party dependencies -- Fixes issue #21, #23 +## 1.1.2 +- Option to preload all pages in memory `PDFViewer(document: document,lazyLoad: false)` -## 1.0.6 +## 1.1.1 +- Option to disable swipe navigation `PDFViewer(document: document,scrollDirection: Aixs.vertical)` +- Option to change scroll axis to vertical or horizontal `PDFViewer(document: document,scrollDirection: Aixs.vertical)` -- Fixed issue in 1.0.5 on iOS that caused xcode build to fail - -## 1.0.5 - -- Fixed bug in iOS where due to caching of Flutter ImageProvider when switching documents old pages would persist -- Added more cases in example demo - -## 1.0.4 - -- Refactored PDFdocument.getAllPages() method (Thanks for @SergioBernal8 for PR ) -- Added white background to page (iOS) -- Changed page resolution in iOS to 300 dpi -- Moved tooltips to a proper class - -## 1.0.3 - -- Added white background to page (Android) -- Fixed cocoapods name -- User can now define tooltips and page selection dialog strings -- Tapping on page indicator now prompts to user to page selection dialog -- Added zoom to PDFPage - -## 1.0.2 - -- Bottom appbar no longer appears if PDF has only one page (Thanks for @markathomas for suggesting this ) -- Fixed opening PDF from assets not working. -- Example now opens file from assets +## 1.1.0 +- Removed rxdart dependency +- Upgraded to androidX +- Added support to optional header while loading document from url +- Auto hide picker for 1 page documents ## 1.0.1 - -- Updated readme.md and added screenshots to package +- Swipe control +- Zoom scale up to 5.0 ## 1.0.0 - -- Initial release \ No newline at end of file +- First upgraded version after fork +- Cool new customization features \ No newline at end of file diff --git a/README.md b/README.md index 9c8f116a..4ce19bf9 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -# flutter_plugin_pdf_viewer +# advance_pdf_viewer -A flutter plugin for handling PDF files. Works on both Android & iOS +A flutter plugin for handling PDF files. Works on both Android & iOS. Originally forked from (https://github.com/CrossPT/flutter_plugin_pdf_viewer). ## Installation -Add *flutter_plugin_pdf_viewer* as a dependency in [your pubspec.yaml file](https://flutter.io/platform-plugins/). +Add *advance_pdf_viewer* as a dependency in [your pubspec.yaml file](https://flutter.io/platform-plugins/). ``` -flutter_plugin_pdf_viewer: any +advance_pdf_viewer: any ``` --- @@ -57,7 +57,7 @@ Use the pre-built PDF Viewer This code produces the following view: -Demo Screenshot 1 +Demo Screenshot 1 --- @@ -66,7 +66,7 @@ This code produces the following view: * Allow password-protected files * ~~Refactor PDFDocument.getAll() method~~ * ~~Increase page resolution~~ -* Add swipe to change page +* ~~Add swipe to change page~~ --- diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs index e8895216..5628deb6 100644 --- a/android/.settings/org.eclipse.buildship.core.prefs +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -1,2 +1,13 @@ +arguments=--scan +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.0-20191016123526+0000)) connection.project.dir= eclipse.preferences.version=1 +gradle.user.home= +java.home=/Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/android/build.gradle b/android/build.gradle index fe588d94..3efafc3c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -26,7 +26,7 @@ android { defaultConfig { minSdkVersion 16 - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } lintOptions { disable 'InvalidPackage' diff --git a/android/gradle.properties b/android/gradle.properties index 8bd86f68..53ae0ae4 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1 +1,3 @@ +android.enableJetifier=true +android.useAndroidX=true org.gradle.jvmargs=-Xmx1536M diff --git a/android/src/main/java/pt/tribeiro/flutter_plugin_pdf_viewer/FlutterPluginPdfViewerPlugin.java b/android/src/main/java/pt/tribeiro/flutter_plugin_pdf_viewer/FlutterPluginPdfViewerPlugin.java index ffe19f3c..9c230013 100644 --- a/android/src/main/java/pt/tribeiro/flutter_plugin_pdf_viewer/FlutterPluginPdfViewerPlugin.java +++ b/android/src/main/java/pt/tribeiro/flutter_plugin_pdf_viewer/FlutterPluginPdfViewerPlugin.java @@ -10,6 +10,7 @@ import java.io.File; import java.io.FileOutputStream; +import java.io.FilenameFilter; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -30,6 +31,7 @@ public class FlutterPluginPdfViewerPlugin implements MethodCallHandler { private HandlerThread handlerThread; private Handler backgroundHandler; private final Object pluginLocker = new Object(); + private final String filePrefix = "FlutterPluginPdfViewer"; /** * Plugin registration. @@ -42,7 +44,7 @@ public static void registerWith(Registrar registrar) { @Override public void onMethodCall(final MethodCall call, final Result result) { - synchronized(pluginLocker){ + synchronized (pluginLocker) { if (backgroundHandler == null) { handlerThread = new HandlerThread("flutterPdfViewer", Process.THREAD_PRIORITY_BACKGROUND); handlerThread.start(); @@ -50,41 +52,42 @@ public void onMethodCall(final MethodCall call, final Result result) { } } final Handler mainThreadHandler = new Handler(); - backgroundHandler.post( + backgroundHandler.post(// new Runnable() { @Override public void run() { switch (call.method) { - case "getNumberOfPages": - final String numResult = getNumberOfPages((String) call.argument("filePath")); - mainThreadHandler.post(new Runnable(){ - @Override - public void run() { - result.success(numResult); - } - }); - break; - case "getPage": - final String pageResult = getPage((String) call.argument("filePath"), (int) call.argument("pageNumber")); - mainThreadHandler.post(new Runnable(){ - @Override - public void run() { - result.success(pageResult); - } - }); - break; - default: - result.notImplemented(); - break; + case "getNumberOfPages": + final String numResult = getNumberOfPages((String) call.argument("filePath")); + mainThreadHandler.post(new Runnable() { + @Override + public void run() { + result.success(numResult); + } + }); + break; + case "getPage": + final String pageResult = getPage((String) call.argument("filePath"), + (int) call.argument("pageNumber")); + mainThreadHandler.post(new Runnable() { + @Override + public void run() { + result.success(pageResult); + } + }); + break; + default: + result.notImplemented(); + break; } } - } - ); + }); } private String getNumberOfPages(String filePath) { File pdf = new File(filePath); try { + clearCacheDir(); PdfRenderer renderer = new PdfRenderer(ParcelFileDescriptor.open(pdf, ParcelFileDescriptor.MODE_READ_ONLY)); Bitmap bitmap; final int pageCount = renderer.getPageCount(); @@ -95,12 +98,39 @@ private String getNumberOfPages(String filePath) { return null; } - private String createTempPreview(Bitmap bmp, String name, int page) { + private boolean clearCacheDir() { + try { + File directory = instance.context().getCacheDir(); + FilenameFilter myFilter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.toLowerCase().startsWith(filePrefix.toLowerCase()); + } + }; + File[] files = directory.listFiles(myFilter); + // Log.d("Cache Files", "Size: " + files.length); + for (int i = 0; i < files.length; i++) { + // Log.d("Files", "FileName: " + files[i].getName()); + files[i].delete(); + } + return true; + } catch (Exception ex) { + ex.printStackTrace(); + return false; + } + } + + private String getFileNameFromPath(String name) { String filePath = name.substring(name.lastIndexOf('/') + 1); - filePath = name.substring(name.lastIndexOf('.')); + filePath = filePath.substring(0, filePath.lastIndexOf('.')); + return String.format("%s-%s", filePrefix, filePath); + } + + private String createTempPreview(Bitmap bmp, String name, int page) { + String fileNameOnly = getFileNameFromPath(name); File file; try { - String fileName = String.format("%s-%d.png", filePath, page); + String fileName = String.format("%s-%d.png", fileNameOnly, page); file = File.createTempFile(fileName, null, instance.context().getCacheDir()); FileOutputStream out = new FileOutputStream(file); bmp.compress(Bitmap.CompressFormat.PNG, 100, out); @@ -113,7 +143,6 @@ private String createTempPreview(Bitmap bmp, String name, int page) { return file.getAbsolutePath(); } - private String getPage(String filePath, int pageNumber) { File pdf = new File(filePath); try { diff --git a/example/android/.settings/org.eclipse.buildship.core.prefs b/example/android/.settings/org.eclipse.buildship.core.prefs index 7338097b..5628deb6 100644 --- a/example/android/.settings/org.eclipse.buildship.core.prefs +++ b/example/android/.settings/org.eclipse.buildship.core.prefs @@ -1,11 +1,11 @@ -arguments= +arguments=--scan auto.sync=false build.scans.enabled=false -connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(5.4)) +connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.0-20191016123526+0000)) connection.project.dir= eclipse.preferences.version=1 gradle.user.home= -java.home= +java.home=/Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home jvm.arguments= offline.mode=false override.workspace.settings=true diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index ab298322..de2e6290 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -38,7 +38,7 @@ android { targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -56,6 +56,6 @@ flutter { dependencies { testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' } diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index c2e1974f..e0cb5b2c 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -10,7 +10,7 @@ FlutterApplication and put your custom class here. --> runApp(MyApp()); @@ -70,9 +70,50 @@ class _MyAppState extends State { title: const Text('FlutterPluginPDFViewer'), ), body: Center( - child: _isLoading - ? Center(child: CircularProgressIndicator()) - : PDFViewer(document: document)), + child: _isLoading + ? Center(child: CircularProgressIndicator()) + : PDFViewer( + document: document, + //uncomment below line to preload all pages + // lazyLoad: false, + // uncomment below line to scroll vertically + // scrollDirection: Axis.vertical, + + //uncomment below code to replace bottom navigation with your own + /* navigationBuilder: + (context, page, totalPages, jumpToPage, animateToPage) { + return ButtonBar( + alignment: MainAxisAlignment.spaceEvenly, + children: [ + IconButton( + icon: Icon(Icons.first_page), + onPressed: () { + jumpToPage()(page: 0); + }, + ), + IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () { + animateToPage(page: page - 2); + }, + ), + IconButton( + icon: Icon(Icons.arrow_forward), + onPressed: () { + animateToPage(page: page); + }, + ), + IconButton( + icon: Icon(Icons.last_page), + onPressed: () { + jumpToPage(page: totalPages - 1); + }, + ), + ], + ); + }, */ + ), + ), ), ); } diff --git a/example/pubspec.lock b/example/pubspec.lock index 13d20a01..cc97528d 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,20 +1,41 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + advance_pdf_viewer: + dependency: "direct dev" + description: + path: ".." + relative: true + source: path + version: "1.1.2" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.2" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.4.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" charcode: dependency: transitive description: @@ -42,7 +63,7 @@ packages: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.0.6" + version: "2.1.3" cupertino_icons: dependency: "direct main" description: @@ -61,28 +82,21 @@ packages: name: flutter_advanced_networkimage url: "https://pub.dartlang.org" source: hosted - version: "0.5.0" + version: "0.7.0" flutter_cache_manager: dependency: transitive description: name: flutter_cache_manager url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" - flutter_plugin_pdf_viewer: - dependency: "direct dev" - description: - path: ".." - relative: true - source: path - version: "1.0.7" + version: "1.1.3" flutter_svg: dependency: transitive description: name: flutter_svg url: "https://pub.dartlang.org" source: hosted - version: "0.13.1" + version: "0.17.3+1" flutter_test: dependency: "direct dev" description: flutter @@ -102,6 +116,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.3" + image: + dependency: transitive + description: + name: image + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.4" infinite_listview: dependency: transitive description: @@ -115,28 +136,28 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.5" + version: "0.12.6" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.1.8" numberpicker: dependency: transitive description: name: numberpicker url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.2.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.6.2" + version: "1.6.4" path_drawing: dependency: transitive description: @@ -157,35 +178,56 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.6.5" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.4" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" pedantic: dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0+1" petitparser: dependency: transitive description: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" - quiver: + version: "2.4.0" + platform: dependency: transitive description: - name: quiver + name: platform url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" - rxdart: + version: "2.2.1" + plugin_platform_interface: dependency: transitive description: - name: rxdart + name: plugin_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + quiver: + dependency: transitive + description: + name: quiver url: "https://pub.dartlang.org" source: hosted - version: "0.21.0" + version: "2.0.5" sky_engine: dependency: transitive description: flutter @@ -225,7 +267,7 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" synchronized: dependency: transitive description: @@ -246,7 +288,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.5" + version: "0.2.11" typed_data: dependency: transitive description: @@ -274,7 +316,7 @@ packages: name: xml url: "https://pub.dartlang.org" source: hosted - version: "3.3.1" + version: "3.5.0" sdks: - dart: ">=2.2.2 <3.0.0" - flutter: ">=1.6.0 <2.0.0" + dart: ">=2.4.0 <3.0.0" + flutter: ">=1.10.0 <2.0.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 643f6743..96dfe4f2 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,5 +1,5 @@ -name: flutter_plugin_pdf_viewer_example -description: Demonstrates how to use the flutter_plugin_pdf_viewer plugin. +name: advance_pdf_viewer_example +description: Demonstrates how to use the advance_pdf_viewer plugin. publish_to: 'none' environment: @@ -17,7 +17,7 @@ dev_dependencies: flutter_test: sdk: flutter - flutter_plugin_pdf_viewer: + advance_pdf_viewer: path: ../ flutter: diff --git a/ios/flutter_plugin_pdf_viewer.podspec b/ios/advance_pdf_viewer.podspec similarity index 93% rename from ios/flutter_plugin_pdf_viewer.podspec rename to ios/advance_pdf_viewer.podspec index 4e1f42be..5786babf 100644 --- a/ios/flutter_plugin_pdf_viewer.podspec +++ b/ios/advance_pdf_viewer.podspec @@ -2,7 +2,7 @@ # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html # Pod::Spec.new do |s| - s.name = 'flutter_plugin_pdf_viewer' + s.name = 'advance_pdf_viewer' s.version = '1.0.5' s.summary = 'Allows you to generate PNG's of specified pages from a provided PDF file source.' s.description = <<-DESC diff --git a/lib/flutter_plugin_pdf_viewer.dart b/lib/advance_pdf_viewer.dart similarity index 60% rename from lib/flutter_plugin_pdf_viewer.dart rename to lib/advance_pdf_viewer.dart index 77a8af18..8461921b 100644 --- a/lib/flutter_plugin_pdf_viewer.dart +++ b/lib/advance_pdf_viewer.dart @@ -1,6 +1,6 @@ -library flutter_plugin_pdf_viewer; +library advance_pdf_viewer; export 'src/document.dart' show PDFDocument; export 'src/page.dart' show PDFPage; -export 'src/viewer.dart' show PDFViewer; +export 'src/viewer.dart' show PDFViewer, IndicatorPosition; export 'src/tooltip.dart' show PDFViewerTooltip; diff --git a/lib/src/document.dart b/lib/src/document.dart index 48442978..1f764e1e 100644 --- a/lib/src/document.dart +++ b/lib/src/document.dart @@ -3,9 +3,8 @@ import 'dart:io'; import 'package:flutter/services.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; -import 'package:flutter_plugin_pdf_viewer/src/page.dart'; +import 'package:advance_pdf_viewer/src/page.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:rxdart/rxdart.dart'; class PDFDocument { static const MethodChannel _channel = @@ -13,6 +12,8 @@ class PDFDocument { String _filePath; int count; + List _pages = []; + bool _preloaded = false; /// Load a PDF File from a given File /// @@ -33,9 +34,10 @@ class PDFDocument { /// Load a PDF File from a given URL. /// File is saved in cache /// - static Future fromURL(String url) async { + static Future fromURL(String url, + {Map headers}) async { // Download into cache - File f = await DefaultCacheManager().getSingleFile(url); + File f = await DefaultCacheManager().getSingleFile(url, headers: headers); PDFDocument document = PDFDocument(); document._filePath = f.path; try { @@ -78,20 +80,45 @@ class PDFDocument { /// Load specific page /// /// [page] defaults to `1` and must be equal or above it - Future get({int page = 1}) async { + Future get( + {int page = 1, final Function(double) onZoomChanged}) async { assert(page > 0); + if (_preloaded && _pages.isNotEmpty) return _pages[page - 1]; var data = await _channel .invokeMethod('getPage', {'filePath': _filePath, 'pageNumber': page}); - return new PDFPage(data, page); + return new PDFPage( + data, + page, + onZoomChanged: onZoomChanged, + ); + } + + Future preloadPages({final Function(double) onZoomChanged}) async { + int countvar = 1; + await Future.forEach(List(count), (i) async { + final data = await _channel.invokeMethod( + 'getPage', {'filePath': _filePath, 'pageNumber': countvar}); + _pages.add(PDFPage( + data, + countvar, + onZoomChanged: onZoomChanged, + )); + countvar++; + }); + _preloaded = true; } // Stream all pages - Observable getAll() { + Stream getAll({final Function(double) onZoomChanged}) { return Future.forEach(List(count), (i) async { print(i); final data = await _channel .invokeMethod('getPage', {'filePath': _filePath, 'pageNumber': i}); - return new PDFPage(data, 1); + return new PDFPage( + data, + 1, + onZoomChanged: onZoomChanged, + ); }).asStream(); } } diff --git a/lib/src/page.dart b/lib/src/page.dart index e85e48d7..b8cfb22b 100644 --- a/lib/src/page.dart +++ b/lib/src/page.dart @@ -7,7 +7,8 @@ import 'package:flutter_advanced_networkimage/zoomable.dart'; class PDFPage extends StatefulWidget { final String imgPath; final int num; - PDFPage(this.imgPath, this.num); + final Function(double) onZoomChanged; + PDFPage(this.imgPath, this.num, {this.onZoomChanged}); @override _PDFPageState createState() => _PDFPageState(); @@ -43,10 +44,11 @@ class _PDFPageState extends State { return Container( decoration: null, child: ZoomableWidget( + onZoomChanged: widget.onZoomChanged, zoomSteps: 3, minScale: 1.0, - panLimit: 0.8, - maxScale: 3.0, + panLimit: 1.0, + maxScale: 5.0, child: Image(image: provider), )); } diff --git a/lib/src/viewer.dart b/lib/src/viewer.dart index 9326a223..723395a0 100644 --- a/lib/src/viewer.dart +++ b/lib/src/viewer.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_plugin_pdf_viewer/flutter_plugin_pdf_viewer.dart'; +import 'package:advance_pdf_viewer/advance_pdf_viewer.dart'; import 'package:numberpicker/numberpicker.dart'; -import 'tooltip.dart'; enum IndicatorPosition { topLeft, topRight, bottomLeft, bottomRight } @@ -14,16 +13,30 @@ class PDFViewer extends StatefulWidget { final bool showPicker; final bool showNavigation; final PDFViewerTooltip tooltip; + final bool enableSwipeNavigation; + final Axis scrollDirection; + final bool lazyLoad; + final Widget Function( + BuildContext, + int pageNumber, + int totalPages, + void Function({int page}) jumpToPage, + void Function({int page}) animateToPage, + ) navigationBuilder; PDFViewer( {Key key, @required this.document, + this.scrollDirection, + this.lazyLoad = true, this.indicatorText = Colors.white, this.indicatorBackground = Colors.black54, this.showIndicator = true, this.showPicker = true, this.showNavigation = true, + this.enableSwipeNavigation = true, this.tooltip = const PDFViewerTooltip(), + this.navigationBuilder, this.indicatorPosition = IndicatorPosition.topRight}) : super(key: key); @@ -33,46 +46,76 @@ class PDFViewer extends StatefulWidget { class _PDFViewerState extends State { bool _isLoading = true; int _pageNumber = 1; - int _oldPage = 0; - PDFPage _page; - List _pages = List(); + bool _swipeEnabled = true; + List _pages; + PageController _pageController; + final Duration animationDuration = Duration(milliseconds: 200); + final Curve animationCurve = Curves.easeIn; + + @override + void initState() { + super.initState(); + _pages = List(widget.document.count); + _pageController = PageController(); + if (!widget.lazyLoad) + widget.document.preloadPages(onZoomChanged: onZoomChanged); + } @override void didChangeDependencies() { super.didChangeDependencies(); - _oldPage = 0; _pageNumber = 1; _isLoading = true; - _pages.clear(); + _pages = List(widget.document.count); + // _loadAllPages(); _loadPage(); } @override void didUpdateWidget(PDFViewer oldWidget) { super.didUpdateWidget(oldWidget); - _oldPage = 0; - _pageNumber = 1; - _isLoading = true; - _pages.clear(); - _loadPage(); } - _loadPage() async { - setState(() => _isLoading = true); - if (_oldPage == 0) { - _page = await widget.document.get(page: _pageNumber); - } else if (_oldPage != _pageNumber) { - _oldPage = _pageNumber; - _page = await widget.document.get(page: _pageNumber); + onZoomChanged(double scale) { + if (scale != 1.0) { + setState(() { + _swipeEnabled = false; + }); + } else { + setState(() { + _swipeEnabled = true; + }); } - if(this.mounted) { - setState(() => _isLoading = false); + } + + _loadPage() async { + if (_pages[_pageNumber - 1] != null) return; + setState(() { + _isLoading = true; + }); + final data = await widget.document + .get(page: _pageNumber, onZoomChanged: onZoomChanged); + _pages[_pageNumber - 1] = data; + if (mounted) { + setState(() { + _isLoading = false; + }); } } + _animateToPage({int page}) { + _pageController.animateToPage(page != null ? page : _pageNumber - 1, + duration: animationDuration, curve: animationCurve); + } + + _jumpToPage({int page}) { + _pageController.jumpToPage(page != null ? page : _pageNumber - 1); + } + Widget _drawIndicator() { Widget child = GestureDetector( - onTap: _pickPage, + onTap: + widget.showPicker && widget.document.count > 1 ? _pickPage : null, child: Container( padding: EdgeInsets.only(top: 4.0, left: 16.0, bottom: 4.0, right: 16.0), @@ -113,7 +156,7 @@ class _PDFViewerState extends State { }).then((int value) { if (value != null) { _pageNumber = value; - _loadPage(); + _jumpToPage(); } }); } @@ -123,13 +166,31 @@ class _PDFViewerState extends State { return Scaffold( body: Stack( children: [ - _isLoading ? Center(child: CircularProgressIndicator()) : _page, + PageView.builder( + physics: _swipeEnabled && widget.enableSwipeNavigation + ? null + : NeverScrollableScrollPhysics(), + onPageChanged: (page) { + setState(() { + _pageNumber = page + 1; + }); + _loadPage(); + }, + scrollDirection: widget.scrollDirection ?? Axis.horizontal, + controller: _pageController, + itemCount: _pages?.length ?? 0, + itemBuilder: (context, index) => _pages[index] == null + ? Center( + child: CircularProgressIndicator(), + ) + : _pages[index], + ), (widget.showIndicator && !_isLoading) ? _drawIndicator() : Container(), ], ), - floatingActionButton: widget.showPicker + floatingActionButton: widget.showPicker && widget.document.count > 1 ? FloatingActionButton( elevation: 4.0, tooltip: widget.tooltip.jump, @@ -141,62 +202,78 @@ class _PDFViewerState extends State { : null, floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, bottomNavigationBar: (widget.showNavigation || widget.document.count > 1) - ? BottomAppBar( - child: new Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - child: IconButton( - icon: Icon(Icons.first_page), - tooltip: widget.tooltip.first, - onPressed: () { - _pageNumber = 1; - _loadPage(); - }, - ), + ? widget.navigationBuilder != null + ? widget.navigationBuilder( + context, + _pageNumber, + widget.document.count, + _jumpToPage, + _animateToPage, + ) + : BottomAppBar( + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: IconButton( + icon: Icon(Icons.first_page), + tooltip: widget.tooltip.first, + onPressed: _pageNumber == 1 + ? null + : () { + _pageNumber = 1; + _jumpToPage(); + }, + ), + ), + Expanded( + child: IconButton( + icon: Icon(Icons.chevron_left), + tooltip: widget.tooltip.previous, + onPressed: _pageNumber == 1 + ? null + : () { + _pageNumber--; + if (1 > _pageNumber) { + _pageNumber = 1; + } + _animateToPage(); + }, + ), + ), + widget.showPicker + ? Expanded(child: Text('')) + : SizedBox(width: 1), + Expanded( + child: IconButton( + icon: Icon(Icons.chevron_right), + tooltip: widget.tooltip.next, + onPressed: _pageNumber == widget.document.count + ? null + : () { + _pageNumber++; + if (widget.document.count < _pageNumber) { + _pageNumber = widget.document.count; + } + _animateToPage(); + }, + ), + ), + Expanded( + child: IconButton( + icon: Icon(Icons.last_page), + tooltip: widget.tooltip.last, + onPressed: _pageNumber == widget.document.count + ? null + : () { + _pageNumber = widget.document.count; + _jumpToPage(); + }, + ), + ), + ], ), - Expanded( - child: IconButton( - icon: Icon(Icons.chevron_left), - tooltip: widget.tooltip.previous, - onPressed: () { - _pageNumber--; - if (1 > _pageNumber) { - _pageNumber = 1; - } - _loadPage(); - }, - ), - ), - widget.showPicker - ? Expanded(child: Text('')) - : SizedBox(width: 1), - Expanded( - child: IconButton( - icon: Icon(Icons.chevron_right), - tooltip: widget.tooltip.next, - onPressed: () { - _pageNumber++; - if (widget.document.count < _pageNumber) { - _pageNumber = widget.document.count; - } - _loadPage(); - }, - ), - ), - Expanded( - child: IconButton( - icon: Icon(Icons.last_page), - tooltip: widget.tooltip.last, - onPressed: () { - _pageNumber = widget.document.count; - _loadPage(); - }, - ), - ), - ], - ), - ) + ) : Container(), ); } diff --git a/pubspec.lock b/pubspec.lock index 3a13e9c4..c771fa22 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -47,21 +47,21 @@ packages: name: flutter_advanced_networkimage url: "https://pub.dartlang.org" source: hosted - version: "0.5.0" + version: "0.7.0" flutter_cache_manager: dependency: "direct main" description: name: flutter_cache_manager url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.3" flutter_svg: dependency: transitive description: name: flutter_svg url: "https://pub.dartlang.org" source: hosted - version: "0.13.1" + version: "0.17.3+1" http: dependency: transitive description: @@ -89,21 +89,21 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.1.8" numberpicker: dependency: "direct main" description: name: numberpicker url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.2.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.6.2" + version: "1.6.4" path_drawing: dependency: transitive description: @@ -124,7 +124,21 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.6.5" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.4" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" pedantic: dependency: transitive description: @@ -139,13 +153,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.4.0" - rxdart: - dependency: "direct main" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.1" + plugin_platform_interface: + dependency: transitive description: - name: rxdart + name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "0.21.0" + version: "1.0.2" sky_engine: dependency: transitive description: flutter @@ -216,4 +237,4 @@ packages: version: "3.5.0" sdks: dart: ">=2.4.0 <3.0.0" - flutter: ">=1.6.0 <2.0.0" + flutter: ">=1.10.0 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3b97efdd..f4266697 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,8 +1,7 @@ -name: flutter_plugin_pdf_viewer +name: advance_pdf_viewer description: A flutter plugin for handling PDF files. Works on both Android & iOS -version: 1.0.7 -author: Tiago Ribeiro -homepage: https://github.com/CrossPT/flutter_plugin_pdf_viewer +version: 1.1.2 +homepage: https://github.com/lohanidamodar/pdf_viewer environment: sdk: ">=2.1.0 <3.0.0" @@ -10,13 +9,12 @@ environment: dependencies: flutter: sdk: flutter - flutter_cache_manager: ^1.0.0 - path_provider: ^1.1.0 - rxdart: ^0.21.0 - numberpicker: ^1.0.0 - flutter_advanced_networkimage: ^0.5.0 + flutter_cache_manager: ^1.1.3 + path_provider: ^1.6.5 + numberpicker: ^1.2.0 + flutter_advanced_networkimage: ^0.7.0 flutter: plugin: androidPackage: pt.tribeiro.flutter_plugin_pdf_viewer - pluginClass: FlutterPluginPdfViewerPlugin \ No newline at end of file + pluginClass: FlutterPluginPdfViewerPlugin