Updated PDF library

This commit is contained in:
Hillel Coren 2020-08-16 16:29:55 +03:00
parent 28ed4f8092
commit 6830619f75
4 changed files with 128 additions and 231 deletions

View File

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:typed_data';
import 'dart:ui'; import 'dart:ui';
import 'package:built_collection/built_collection.dart'; import 'package:built_collection/built_collection.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -50,8 +51,7 @@ class _DesignEditState extends State<DesignEdit>
FocusScopeNode _focusNode; FocusScopeNode _focusNode;
TabController _tabController; TabController _tabController;
PDFPageImage _pdfPageImage; Uint8List _pdfBytes;
String _pdfString;
bool _isLoading = false; bool _isLoading = false;
List<TextEditingController> _controllers; List<TextEditingController> _controllers;
@ -80,11 +80,11 @@ class _DesignEditState extends State<DesignEdit>
final design = widget.viewModel.design; final design = widget.viewModel.design;
_nameController.text = design.name; _nameController.text = design.name;
_headerController.text = design.getSection(kDesignHeader); //design.design; _headerController.text = design.getSection(kDesignHeader);
_footerController.text = design.getSection(kDesignFooter); //design.design; _footerController.text = design.getSection(kDesignFooter);
_bodyController.text = design.getSection(kDesignBody); //design.design; _bodyController.text = design.getSection(kDesignBody);
_productsController.text = _productsController.text =
design.getSection(kDesignProducts); //design.design; design.getSection(kDesignProducts);
_tasksController.text = design.getSection(kDesignTasks); _tasksController.text = design.getSection(kDesignTasks);
_includesController.text = design.getSection(kDesignIncludes); _includesController.text = design.getSection(kDesignIncludes);
@ -156,29 +156,13 @@ class _DesignEditState extends State<DesignEdit>
return; return;
} }
if (response == null) {
setState(() { setState(() {
_isLoading = false; _isLoading = false;
}); if (response != null) {
} else if (kIsWeb) { _pdfBytes = response.bodyBytes;
setState(() {
_isLoading = false;
_pdfString = 'data:application/pdf;base64,' +
base64Encode(response.bodyBytes);
});
} else {
final document = await PDFDocument.openData(response.bodyBytes);
final page = await document.getPage(1);
final pageImage =
await page.render(width: page.width, height: page.height);
page.close();
setState(() {
_isLoading = false;
_pdfPageImage = pageImage;
});
} }
}); });
});
} }
@override @override
@ -234,8 +218,7 @@ class _DesignEditState extends State<DesignEdit>
onLoadDesign: _loadDesign, onLoadDesign: _loadDesign,
), ),
DesignPreview( DesignPreview(
pdfPageImage: _pdfPageImage, pdfBytes: _pdfBytes,
pdfString: _pdfString,
isLoading: _isLoading, isLoading: _isLoading,
), ),
DesignSection(textController: _headerController), DesignSection(textController: _headerController),
@ -292,8 +275,7 @@ class _DesignEditState extends State<DesignEdit>
), ),
Expanded( Expanded(
child: DesignPreview( child: DesignPreview(
pdfPageImage: _pdfPageImage, pdfBytes: _pdfBytes,
pdfString: _pdfString,
isLoading: _isLoading, isLoading: _isLoading,
), ),
), ),
@ -373,13 +355,12 @@ class DesignSettings extends StatelessWidget {
class DesignPreview extends StatefulWidget { class DesignPreview extends StatefulWidget {
const DesignPreview({ const DesignPreview({
@required this.pdfString, @required this.pdfBytes,
@required this.pdfPageImage,
@required this.isLoading, @required this.isLoading,
}); });
final String pdfString; final Uint8List pdfBytes;
final PDFPageImage pdfPageImage;
final bool isLoading; final bool isLoading;
@override @override
@ -387,41 +368,30 @@ class DesignPreview extends StatefulWidget {
} }
class _DesignPreviewState extends State<DesignPreview> { class _DesignPreviewState extends State<DesignPreview> {
double _scrollPosition = 0; PdfController _pdfController;
final _scrollController = ScrollController(
//initialScrollOffset: 0,
keepScrollOffset: true,
);
@override String get _pdfString =>
void initState() { 'data:application/pdf;base64,' + base64Encode(widget.pdfBytes);
super.initState();
_scrollController.addListener(onScrolled);
}
void onScrolled() {
_scrollPosition = _scrollController.offset;
}
@override @override
void didUpdateWidget(oldWidget) { void didUpdateWidget(oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (kIsWeb) { if (kIsWeb) {
WebUtils.registerWebView(widget.pdfString); WebUtils.registerWebView(_pdfString);
} else {
final document = PdfDocument.openData(widget.pdfBytes);
if (_pdfController == null) {
_pdfController = PdfController(document: document);
} else {
_pdfController.loadDocument(document);
} }
if (_scrollController.hasClients && _scrollPosition > 0) {
WidgetsBinding.instance.addPostFrameCallback((duration) {
_scrollController.jumpTo(_scrollPosition);
});
} }
} }
@override @override
void dispose() { void dispose() {
_scrollController.removeListener(onScrolled); _pdfController.dispose();
_scrollController.dispose();
super.dispose(); super.dispose();
} }
@ -434,26 +404,19 @@ class _DesignPreviewState extends State<DesignPreview> {
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: <Widget>[ children: <Widget>[
if (widget.pdfPageImage != null) if (kIsWeb)
SingleChildScrollView( HtmlElementView(viewType: _pdfString)
controller: _scrollController, else if (_pdfController != null)
padding: const EdgeInsets.all(6), Padding(
child: Card( padding: const EdgeInsets.all(8),
elevation: 6, child: PdfView(
child: ExtendedImage.memory( controller: _pdfController,
widget.pdfPageImage.bytes, scrollDirection:
fit: BoxFit.fitHeight, isMobile(context) ? Axis.vertical : Axis.horizontal,
alignment: Alignment.topCenter,
),
), ),
) )
else if (widget.pdfString != null)
HtmlElementView(viewType: widget.pdfString)
else else
SizedBox( SizedBox(),
width: double.infinity,
height: double.infinity,
),
if (widget.isLoading) if (widget.isLoading)
Column( Column(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,

View File

@ -13,29 +13,15 @@ import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart'; import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/utils/dialogs.dart'; import 'package:invoiceninja_flutter/utils/dialogs.dart';
import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'package:native_pdf_view/native_pdf_view.dart'; import 'package:native_pdf_view/native_pdf_view.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:native_pdf_renderer/native_pdf_renderer.dart';
import 'package:invoiceninja_flutter/utils/web_stub.dart' import 'package:invoiceninja_flutter/utils/web_stub.dart'
if (dart.library.html) 'package:invoiceninja_flutter/utils/web.dart'; if (dart.library.html) 'package:invoiceninja_flutter/utils/web.dart';
Future<Null> viewPdf(InvoiceEntity invoice, BuildContext context, Future<Null> viewPdf(InvoiceEntity invoice, BuildContext context,
{String activityId}) async { {String activityId}) async {
/*
final localization = AppLocalization.of(context);
if (Platform.isIOS) {
if (await canLaunch(invoice.invitationBorderlessLink)) {
await launch(invoice.invitationBorderlessLink,
forceSafariVC: true, forceWebView: true);
} else {
throw localization.anErrorOccurred;
}
return;
}
*/
showDialog<Scaffold>( showDialog<Scaffold>(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
@ -58,8 +44,8 @@ class PDFScaffold extends StatefulWidget {
class _PDFScaffoldState extends State<PDFScaffold> { class _PDFScaffoldState extends State<PDFScaffold> {
String _pdfString; String _pdfString;
List<PDFPageImage> _pdfImages;
http.Response _response; http.Response _response;
PdfController _pdfController;
@override @override
void didChangeDependencies() { void didChangeDependencies() {
@ -69,27 +55,29 @@ class _PDFScaffoldState extends State<PDFScaffold> {
setState(() { setState(() {
_response = response; _response = response;
}); });
if (kIsWeb) { if (kIsWeb) {
renderWebPDF( _pdfString =
context: context, 'data:application/pdf;base64,' + base64Encode(response.bodyBytes);
invoice: widget.invoice,
response: response,
).then((value) => setState(() {
_pdfString = value;
WebUtils.registerWebView(_pdfString); WebUtils.registerWebView(_pdfString);
}));
} else { } else {
renderMobilePDF( final document = PdfDocument.openData(_response.bodyBytes);
context: context, if (_pdfController == null) {
invoice: widget.invoice, _pdfController = PdfController(document: document);
response: response, } else {
).then((value) => setState(() { _pdfController.loadDocument(document);
_pdfImages = value; }
}));
} }
}); });
} }
@override
void dispose() {
_pdfController?.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final store = StoreProvider.of<AppState>(context); final store = StoreProvider.of<AppState>(context);
@ -124,58 +112,21 @@ class _PDFScaffoldState extends State<PDFScaffold> {
final pdfData = file.File(filePath); final pdfData = file.File(filePath);
pdfData.writeAsBytes(_response.bodyBytes); pdfData.writeAsBytes(_response.bodyBytes);
await FlutterShare.shareFile( await FlutterShare.shareFile(
title: 'test.pdf', title: 'test.pdf', filePath: filePath);
filePath: filePath);
} }
}, },
), ),
], ],
), ),
body: kIsWeb body: _pdfString == null && _pdfController == null
? _pdfString == null
? LoadingIndicator() ? LoadingIndicator()
: _pdfString == '' : kIsWeb
? SizedBox() ? HtmlElementView(viewType: _pdfString)
: HtmlElementView(viewType: _pdfString) : PdfView(
: _pdfImages == null controller: _pdfController,
? LoadingIndicator() scrollDirection:
: _pdfImages.isEmpty isMobile(context) ? Axis.vertical : Axis.horizontal,
? SizedBox() ));
: Container(
color: Colors.grey,
padding: const EdgeInsets.symmetric(vertical: 16),
child: _pdfImages.length == 1
? Center(
child: Container(
color: Colors.white,
child: Image(
image: MemoryImage(_pdfImages.first.bytes),
height: double.infinity),
),
)
: ListView(
scrollDirection: Axis.horizontal,
children: _pdfImages
.map((page) => Row(
children: <Widget>[
Container(
width: 20,
height: double.infinity,
color: Colors.grey,
),
Container(
color: Colors.white,
child: ExtendedImage.memory(
page.bytes,
fit: BoxFit.fitHeight,
),
),
],
))
.toList(),
),
),
);
} }
} }
@ -205,37 +156,3 @@ Future<Response> _loadPDF(
return response; return response;
} }
Future<String> renderWebPDF({
@required BuildContext context,
@required http.Response response,
@required InvoiceEntity invoice,
}) async {
if (response == null) {
return '';
}
return 'data:application/pdf;base64,' + base64Encode(response.bodyBytes);
}
Future<List<PDFPageImage>> renderMobilePDF({
@required BuildContext context,
@required http.Response response,
@required InvoiceEntity invoice,
}) async {
final List<PDFPageImage> pages = [];
if (response == null) {
return pages;
}
final document = await PDFDocument.openData(response.bodyBytes);
for (var i = 1; i <= document.pagesCount; i++) {
final page = await document.getPage(i);
final pageImage = await page.render(width: page.width, height: page.height);
pages.add(pageImage);
page.close();
}
return pages;
}

View File

@ -219,12 +219,12 @@ packages:
source: hosted source: hosted
version: "0.4.2+6" version: "0.4.2+6"
extended_image: extended_image:
dependency: "direct overridden" dependency: transitive
description: description:
name: extended_image name: extended_image
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.7.3-dev" version: "1.1.0"
extended_image_library: extended_image_library:
dependency: transitive dependency: transitive
description: description:
@ -238,7 +238,7 @@ packages:
name: extension name: extension
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.5" version: "0.1.1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -488,6 +488,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.1.4" version: "3.1.4"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.14"
image_picker: image_picker:
dependency: "direct main" dependency: "direct main"
description: description:
@ -592,14 +599,14 @@ packages:
name: native_pdf_renderer name: native_pdf_renderer
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.1" version: "2.3.2"
native_pdf_view: native_pdf_view:
dependency: "direct main" dependency: "direct main"
description: description:
name: native_pdf_view name: native_pdf_view
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.2.0" version: "3.8.0"
node_interop: node_interop:
dependency: transitive dependency: transitive
description: description:
@ -677,6 +684,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.10.0-nullsafety" version: "1.10.0-nullsafety"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@ -1010,7 +1024,7 @@ packages:
name: url_launcher_web name: url_launcher_web
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.2" version: "0.1.2+1"
usage: usage:
dependency: transitive dependency: transitive
description: description:
@ -1095,6 +1109,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.0" version: "0.1.0"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.0"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
@ -1104,4 +1125,4 @@ packages:
version: "2.2.1" version: "2.2.1"
sdks: sdks:
dart: ">=2.10.0-0.0.dev <2.10.0" dart: ">=2.10.0-0.0.dev <2.10.0"
flutter: ">=1.12.13+hotfix.5 <2.0.0" flutter: ">=1.17.0 <2.0.0"

View File

@ -38,7 +38,7 @@ dependencies:
flutter_json_widget: ^1.0.2 flutter_json_widget: ^1.0.2
webview_flutter: ^0.3.19+8 webview_flutter: ^0.3.19+8
timeago: ^2.0.26 timeago: ^2.0.26
native_pdf_view: ^2.2.0 native_pdf_view: ^3.8.0
#flutter_typeahead: 1.8.0 #flutter_typeahead: 1.8.0
flutter_typeahead: flutter_typeahead:
git: git:
@ -51,10 +51,6 @@ dependencies:
version: ^1.0.0 version: ^1.0.0
#idb_shim: ^1.11.1+1 #idb_shim: ^1.11.1+1
dependency_overrides:
# Error: No named parameter with the name 'animation'
extended_image: 0.7.3-dev
dev_dependencies: dev_dependencies:
flutter_driver: flutter_driver:
sdk: flutter sdk: flutter