Showing
24 changed files
with
1028 additions
and
586 deletions
@@ -34,11 +34,11 @@ printing/android/.gradle | @@ -34,11 +34,11 @@ printing/android/.gradle | ||
34 | pedantic_analyis_options_*.yaml | 34 | pedantic_analyis_options_*.yaml |
35 | .dartfix | 35 | .dartfix |
36 | node_modules | 36 | node_modules |
37 | -pdf/lcov.info | ||
38 | -pdf/coverage.json | 37 | +lcov.info |
38 | +coverage.json | ||
39 | .coverage | 39 | .coverage |
40 | package-lock.json | 40 | package-lock.json |
41 | -printing/lcov.info | 41 | +lcov.info |
42 | 42 | ||
43 | test/readme.dart | 43 | test/readme.dart |
44 | test/android | 44 | test/android |
@@ -77,18 +77,18 @@ test-pdf: $(FONTS) get-pdf .coverage | @@ -77,18 +77,18 @@ test-pdf: $(FONTS) get-pdf .coverage | ||
77 | 77 | ||
78 | test-printing: $(FONTS) get-printing .coverage | 78 | test-printing: $(FONTS) get-printing .coverage |
79 | cd printing; flutter test --coverage --coverage-path lcov.info | 79 | cd printing; flutter test --coverage --coverage-path lcov.info |
80 | - cd printing/example; flutter test --coverage --coverage-path ../lcov.info | 80 | + cd printing/example; flutter test --coverage --coverage-path lcov.info |
81 | 81 | ||
82 | test-readme: $(FONTS) get-readme | 82 | test-readme: $(FONTS) get-readme |
83 | cd test; dart extract_readme.dart | 83 | cd test; dart extract_readme.dart |
84 | - cd test; dartanalyzer readme.dart | 84 | + cd test; dartanalyzer readme.dart |
85 | 85 | ||
86 | test-web: | 86 | test-web: |
87 | cd pdf/web_example; pub get | 87 | cd pdf/web_example; pub get |
88 | cd pdf/web_example; pub run webdev build | 88 | cd pdf/web_example; pub run webdev build |
89 | 89 | ||
90 | test: test-pdf test-printing node_modules test-web | 90 | test: test-pdf test-printing node_modules test-web |
91 | - cat pdf/lcov.info printing/lcov.info | node_modules/.bin/lcov-summary | 91 | + cat pdf/lcov.info printing/lcov.info printing/example/lcov.info | node_modules/.bin/lcov-summary |
92 | 92 | ||
93 | clean: | 93 | clean: |
94 | git clean -fdx -e .vscode -e ref | 94 | git clean -fdx -e .vscode -e ref |
@@ -101,6 +101,14 @@ abstract class PdfFont extends PdfObject { | @@ -101,6 +101,14 @@ abstract class PdfFont extends PdfObject { | ||
101 | pdfDocument, 'ZapfDingbats', 0.820, -0.143, _zapfDingbatsWidths); | 101 | pdfDocument, 'ZapfDingbats', 0.820, -0.143, _zapfDingbatsWidths); |
102 | } | 102 | } |
103 | 103 | ||
104 | + static const String _cannotDecodeMessage = | ||
105 | + '''--------------------------------------------- | ||
106 | +Cannot decode the string to Latin1. | ||
107 | +This font does not support Unicode characters. | ||
108 | +If you want to use strings other than Latin strings, use a TrueType (TTF) font instead. | ||
109 | +See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | ||
110 | +---------------------------------------------'''; | ||
111 | + | ||
104 | /// The df type of the font, usually /Type1 | 112 | /// The df type of the font, usually /Type1 |
105 | final String subtype; | 113 | final String subtype; |
106 | 114 | ||
@@ -141,13 +149,12 @@ abstract class PdfFont extends PdfObject { | @@ -141,13 +149,12 @@ abstract class PdfFont extends PdfObject { | ||
141 | final Uint8List chars = latin1.encode(s); | 149 | final Uint8List chars = latin1.encode(s); |
142 | final Iterable<PdfFontMetrics> metrics = chars.map(glyphMetrics); | 150 | final Iterable<PdfFontMetrics> metrics = chars.map(glyphMetrics); |
143 | return PdfFontMetrics.append(metrics); | 151 | return PdfFontMetrics.append(metrics); |
144 | - } catch (e) { | ||
145 | - assert(false, '''\n--------------------------------------------- | ||
146 | -Can not decode the string to Latin1. | ||
147 | -This font does not support Unicode characters. | ||
148 | -If you want to use strings other than Latin strings, use a TrueType (TTF) font instead. | ||
149 | -See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | ||
150 | ----------------------------------------------'''); | 152 | + } catch (_) { |
153 | + assert(() { | ||
154 | + print(_cannotDecodeMessage); | ||
155 | + return true; | ||
156 | + }()); | ||
157 | + | ||
151 | rethrow; | 158 | rethrow; |
152 | } | 159 | } |
153 | } | 160 | } |
@@ -169,13 +176,12 @@ See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | @@ -169,13 +176,12 @@ See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | ||
169 | ..putByte(40) | 176 | ..putByte(40) |
170 | ..putTextBytes(latin1.encode(text)) | 177 | ..putTextBytes(latin1.encode(text)) |
171 | ..putByte(41); | 178 | ..putByte(41); |
172 | - } catch (e) { | ||
173 | - assert(false, '''\n--------------------------------------------- | ||
174 | -Can not decode the string to Latin1. | ||
175 | -This font does not support Unicode characters. | ||
176 | -If you want to use strings other than Latin strings, use a TrueType (TTF) font instead. | ||
177 | -See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | ||
178 | ----------------------------------------------'''); | 179 | + } catch (_) { |
180 | + assert(() { | ||
181 | + print(_cannotDecodeMessage); | ||
182 | + return true; | ||
183 | + }()); | ||
184 | + | ||
179 | rethrow; | 185 | rethrow; |
180 | } | 186 | } |
181 | } | 187 | } |
@@ -63,11 +63,17 @@ class MyAppState extends State<MyApp> { | @@ -63,11 +63,17 @@ class MyAppState extends State<MyApp> { | ||
63 | 63 | ||
64 | Future<void> _printPdf() async { | 64 | Future<void> _printPdf() async { |
65 | print('Print ...'); | 65 | print('Print ...'); |
66 | - final bool result = await Printing.layoutPdf( | ||
67 | - onLayout: (PdfPageFormat format) async => | ||
68 | - (await generateDocument(format)).save()); | ||
69 | - | ||
70 | - _showPrintedToast(result); | 66 | + try { |
67 | + final bool result = await Printing.layoutPdf( | ||
68 | + onLayout: (PdfPageFormat format) async => | ||
69 | + (await generateDocument(format)).save()); | ||
70 | + _showPrintedToast(result); | ||
71 | + } catch (e) { | ||
72 | + final ScaffoldState scaffold = Scaffold.of(shareWidget.currentContext); | ||
73 | + scaffold.showSnackBar(SnackBar( | ||
74 | + content: Text('Error: ${e.toString()}'), | ||
75 | + )); | ||
76 | + } | ||
71 | } | 77 | } |
72 | 78 | ||
73 | Future<void> _saveAsFile() async { | 79 | Future<void> _saveAsFile() async { |
@@ -14,22 +14,9 @@ | @@ -14,22 +14,9 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | -library printing; | ||
18 | - | ||
19 | -import 'dart:async'; | ||
20 | -import 'dart:typed_data'; | ||
21 | -import 'dart:ui' as ui; | ||
22 | - | ||
23 | -import 'package:flutter/rendering.dart'; | ||
24 | -import 'package:flutter/services.dart'; | ||
25 | -import 'package:flutter/widgets.dart'; | ||
26 | -import 'package:pdf/pdf.dart'; | ||
27 | -import 'package:pdf/widgets.dart'; | ||
28 | - | ||
29 | -part 'src/asset_utils.dart'; | ||
30 | -part 'src/print_job.dart'; | ||
31 | -part 'src/printer.dart'; | ||
32 | -part 'src/printing.dart'; | ||
33 | -part 'src/printing_info.dart'; | ||
34 | -part 'src/raster.dart'; | ||
35 | -part 'src/widgets.dart'; | 17 | +export 'src/asset_utils.dart'; |
18 | +export 'src/callback.dart'; | ||
19 | +export 'src/printer.dart'; | ||
20 | +export 'src/printing.dart'; | ||
21 | +export 'src/printing_info.dart'; | ||
22 | +export 'src/raster.dart'; |
printing/lib/printing_web.dart
deleted
100644 → 0
1 | -/* | ||
2 | - * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | - | ||
17 | -library printing_web; | ||
18 | - | ||
19 | -import 'dart:async'; | ||
20 | -import 'dart:html' as html; | ||
21 | -import 'dart:js' as js; | ||
22 | - | ||
23 | -import 'package:flutter/services.dart'; | ||
24 | -import 'package:flutter_web_plugins/flutter_web_plugins.dart'; | ||
25 | - | ||
26 | -part 'wsrc/print_job.dart'; | ||
27 | - | ||
28 | -class PrintingPlugin { | ||
29 | - PrintingPlugin(this._channel); | ||
30 | - | ||
31 | - static void registerWith(Registrar registrar) { | ||
32 | - final MethodChannel channel = MethodChannel( | ||
33 | - 'net.nfet.printing', | ||
34 | - const StandardMethodCodec(), | ||
35 | - registrar.messenger, | ||
36 | - ); | ||
37 | - final PrintingPlugin instance = PrintingPlugin(channel); | ||
38 | - channel.setMethodCallHandler(instance.handleMethodCall); | ||
39 | - } | ||
40 | - | ||
41 | - final MethodChannel _channel; | ||
42 | - | ||
43 | - Future<dynamic> handleMethodCall(MethodCall call) async { | ||
44 | - switch (call.method) { | ||
45 | - case 'printPdf': | ||
46 | - final String name = call.arguments['name']; | ||
47 | - final double width = call.arguments['width']; | ||
48 | - final double height = call.arguments['height']; | ||
49 | - final double marginLeft = call.arguments['marginLeft']; | ||
50 | - final double marginTop = call.arguments['marginTop']; | ||
51 | - final double marginRight = call.arguments['marginRight']; | ||
52 | - final double marginBottom = call.arguments['marginBottom']; | ||
53 | - | ||
54 | - final _PrintJob printJob = _PrintJob(this, call.arguments['job']); | ||
55 | - return printJob.printPdf(name, width, height, marginLeft, marginTop, | ||
56 | - marginRight, marginBottom); | ||
57 | - case 'sharePdf': | ||
58 | - final List<int> data = call.arguments['doc']; | ||
59 | - final double x = call.arguments['x']; | ||
60 | - final double y = call.arguments['y']; | ||
61 | - final double width = call.arguments['w']; | ||
62 | - final double height = call.arguments['h']; | ||
63 | - final String name = call.arguments['name']; | ||
64 | - return _PrintJob.sharePdf(data, x, y, width, height, name); | ||
65 | - case 'printingInfo': | ||
66 | - return _PrintJob.printingInfo(); | ||
67 | - } | ||
68 | - throw UnimplementedError('Method "${call.method}" not implemented'); | ||
69 | - } | ||
70 | - | ||
71 | - /// Request the Pdf document from flutter | ||
72 | - Future<void> onLayout( | ||
73 | - _PrintJob printJob, | ||
74 | - double width, | ||
75 | - double height, | ||
76 | - double marginLeft, | ||
77 | - double marginTop, | ||
78 | - double marginRight, | ||
79 | - double marginBottom) async { | ||
80 | - final Map<String, dynamic> args = <String, dynamic>{ | ||
81 | - 'width': width, | ||
82 | - 'height': height, | ||
83 | - 'marginLeft': marginLeft, | ||
84 | - 'marginTop': marginTop, | ||
85 | - 'marginRight': marginRight, | ||
86 | - 'marginBottom': marginBottom, | ||
87 | - 'job': printJob.index, | ||
88 | - }; | ||
89 | - | ||
90 | - final dynamic result = | ||
91 | - await _channel.invokeMethod<dynamic>('onLayout', args); | ||
92 | - | ||
93 | - if (result is List<int>) { | ||
94 | - printJob.setDocument(result); | ||
95 | - } else { | ||
96 | - printJob.cancelJob(); | ||
97 | - } | ||
98 | - } | ||
99 | - | ||
100 | - /// send completion status to flutter | ||
101 | - Future<void> onCompleted(_PrintJob printJob, bool completed, | ||
102 | - [String error = '']) async { | ||
103 | - final Map<String, dynamic> data = <String, dynamic>{ | ||
104 | - 'completed': completed, | ||
105 | - 'error': error, | ||
106 | - 'job': printJob.index, | ||
107 | - }; | ||
108 | - | ||
109 | - await _channel.invokeMethod<dynamic>('onCompleted', data); | ||
110 | - } | ||
111 | -} |
@@ -14,7 +14,15 @@ | @@ -14,7 +14,15 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | -part of printing; | 17 | +import 'dart:async'; |
18 | +import 'dart:typed_data'; | ||
19 | +import 'dart:ui' as ui; | ||
20 | + | ||
21 | +import 'package:flutter/rendering.dart'; | ||
22 | +import 'package:flutter/services.dart'; | ||
23 | +import 'package:meta/meta.dart'; | ||
24 | +import 'package:pdf/pdf.dart'; | ||
25 | +import 'package:pdf/widgets.dart'; | ||
18 | 26 | ||
19 | /// Loads an image from a Flutter [ui.Image] | 27 | /// Loads an image from a Flutter [ui.Image] |
20 | /// into a [PdfImage] instance | 28 | /// into a [PdfImage] instance |
printing/lib/src/callback.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +import 'dart:async'; | ||
18 | + | ||
19 | +import 'package:pdf/pdf.dart'; | ||
20 | + | ||
21 | +/// Callback used to generate the Pdf document dynamically when the user | ||
22 | +/// changes the page settings: size and margins | ||
23 | +typedef LayoutCallback = FutureOr<List<int>> Function(PdfPageFormat format); |
printing/lib/src/interface.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +import 'dart:async'; | ||
18 | + | ||
19 | +import 'package:flutter/rendering.dart' show Rect; | ||
20 | +import 'package:pdf/pdf.dart'; | ||
21 | +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; | ||
22 | + | ||
23 | +import 'callback.dart'; | ||
24 | +import 'method_channel.dart'; | ||
25 | +import 'printer.dart'; | ||
26 | +import 'printing_info.dart'; | ||
27 | +import 'raster.dart'; | ||
28 | + | ||
29 | +/// The interface that implementations of printing must implement. | ||
30 | +abstract class PrintingPlatform extends PlatformInterface { | ||
31 | + /// Constructs a UrlLauncherPlatform. | ||
32 | + PrintingPlatform() : super(token: _token); | ||
33 | + | ||
34 | + static final Object _token = Object(); | ||
35 | + | ||
36 | + static PrintingPlatform _instance = MethodChannelPrinting(); | ||
37 | + | ||
38 | + /// The default instance of [PrintingPlatform] to use. | ||
39 | + /// | ||
40 | + /// Defaults to [MethodChannelPrinting]. | ||
41 | + static PrintingPlatform get instance => _instance; | ||
42 | + | ||
43 | + /// Platform-specific plugins should set this with their own platform-specific | ||
44 | + /// class that extends [PrintingPlatform] when they register themselves. | ||
45 | + static set instance(PrintingPlatform instance) { | ||
46 | + PlatformInterface.verifyToken(instance, _token); | ||
47 | + _instance = instance; | ||
48 | + } | ||
49 | + | ||
50 | + /// Returns a [PrintingInfo] object representing the capabilities | ||
51 | + /// supported for the current platform | ||
52 | + Future<PrintingInfo> info(); | ||
53 | + | ||
54 | + /// Prints a Pdf document to a local printer using the platform UI | ||
55 | + /// the Pdf document is re-built in a [LayoutCallback] each time the | ||
56 | + /// user changes a setting like the page format or orientation. | ||
57 | + /// | ||
58 | + /// returns a future with a `bool` set to true if the document is printed | ||
59 | + /// and false if it is canceled. | ||
60 | + /// throws an exception in case of error | ||
61 | + Future<bool> layoutPdf( | ||
62 | + LayoutCallback onLayout, | ||
63 | + String name, | ||
64 | + PdfPageFormat format, | ||
65 | + ); | ||
66 | + | ||
67 | + /// Opens the native printer picker interface, and returns the URL of the selected printer. | ||
68 | + Future<Printer> pickPrinter(Rect bounds); | ||
69 | + | ||
70 | + /// Prints a Pdf document to a specific local printer with no UI | ||
71 | + /// | ||
72 | + /// returns a future with a `bool` set to true if the document is printed | ||
73 | + /// and false if it is canceled. | ||
74 | + /// throws an exception in case of error | ||
75 | + Future<bool> directPrintPdf( | ||
76 | + Printer printer, | ||
77 | + LayoutCallback onLayout, | ||
78 | + String name, | ||
79 | + PdfPageFormat format, | ||
80 | + ); | ||
81 | + | ||
82 | + /// Displays a platform popup to share the Pdf document to another application | ||
83 | + Future<bool> sharePdf( | ||
84 | + List<int> bytes, | ||
85 | + String filename, | ||
86 | + Rect bounds, | ||
87 | + ); | ||
88 | + | ||
89 | + /// Convert an html document to a pdf data | ||
90 | + Future<List<int>> convertHtml( | ||
91 | + String html, | ||
92 | + String baseUrl, | ||
93 | + PdfPageFormat format, | ||
94 | + ); | ||
95 | + | ||
96 | + /// Convert a Pdf document to bitmap images | ||
97 | + Stream<PdfRaster> raster( | ||
98 | + List<int> document, | ||
99 | + List<int> pages, | ||
100 | + double dpi, | ||
101 | + ); | ||
102 | +} |
printing/lib/src/method_channel.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +import 'dart:async'; | ||
18 | +import 'dart:typed_data'; | ||
19 | + | ||
20 | +import 'package:flutter/rendering.dart' show Rect; | ||
21 | +import 'package:flutter/services.dart'; | ||
22 | +import 'package:pdf/pdf.dart'; | ||
23 | + | ||
24 | +import 'callback.dart'; | ||
25 | +import 'interface.dart'; | ||
26 | +import 'print_job.dart'; | ||
27 | +import 'printer.dart'; | ||
28 | +import 'printing_info.dart'; | ||
29 | +import 'raster.dart'; | ||
30 | + | ||
31 | +const MethodChannel _channel = MethodChannel('net.nfet.printing'); | ||
32 | + | ||
33 | +/// An implementation of [PrintingPlatform] that uses method channels. | ||
34 | +class MethodChannelPrinting extends PrintingPlatform { | ||
35 | + MethodChannelPrinting() : super() { | ||
36 | + _channel.setMethodCallHandler(_handleMethod); | ||
37 | + } | ||
38 | + | ||
39 | + static final Map<int, PrintJob> _printJobs = <int, PrintJob>{}; | ||
40 | + static int _jobIndex = 0; | ||
41 | + | ||
42 | + /// Callbacks from platform plugins | ||
43 | + static Future<dynamic> _handleMethod(MethodCall call) async { | ||
44 | + switch (call.method) { | ||
45 | + case 'onLayout': | ||
46 | + final PrintJob job = _printJobs[call.arguments['job']]; | ||
47 | + try { | ||
48 | + final PdfPageFormat format = PdfPageFormat( | ||
49 | + call.arguments['width'], | ||
50 | + call.arguments['height'], | ||
51 | + marginLeft: call.arguments['marginLeft'], | ||
52 | + marginTop: call.arguments['marginTop'], | ||
53 | + marginRight: call.arguments['marginRight'], | ||
54 | + marginBottom: call.arguments['marginBottom'], | ||
55 | + ); | ||
56 | + | ||
57 | + final List<int> bytes = await job.onLayout(format); | ||
58 | + | ||
59 | + if (bytes == null) { | ||
60 | + throw 'onLayout returned null'; | ||
61 | + } | ||
62 | + | ||
63 | + return Uint8List.fromList(bytes); | ||
64 | + } catch (e) { | ||
65 | + return e.toString(); | ||
66 | + } | ||
67 | + break; | ||
68 | + case 'onCompleted': | ||
69 | + final bool completed = call.arguments['completed']; | ||
70 | + final String error = call.arguments['error']; | ||
71 | + final PrintJob job = _printJobs[call.arguments['job']]; | ||
72 | + if (completed == false && error != null) { | ||
73 | + job.onCompleted.completeError(error); | ||
74 | + } else { | ||
75 | + job.onCompleted.complete(completed); | ||
76 | + } | ||
77 | + break; | ||
78 | + case 'onHtmlRendered': | ||
79 | + final PrintJob job = _printJobs[call.arguments['job']]; | ||
80 | + job.onHtmlRendered.complete(call.arguments['doc']); | ||
81 | + break; | ||
82 | + case 'onHtmlError': | ||
83 | + final PrintJob job = _printJobs[call.arguments['job']]; | ||
84 | + job.onHtmlRendered.completeError(call.arguments['error']); | ||
85 | + break; | ||
86 | + case 'onPageRasterized': | ||
87 | + final PrintJob job = _printJobs[call.arguments['job']]; | ||
88 | + final PdfRaster raster = PdfRaster( | ||
89 | + call.arguments['width'], | ||
90 | + call.arguments['height'], | ||
91 | + call.arguments['image'], | ||
92 | + ); | ||
93 | + job.onPageRasterized.add(raster); | ||
94 | + break; | ||
95 | + case 'onPageRasterEnd': | ||
96 | + final PrintJob job = _printJobs[call.arguments['job']]; | ||
97 | + job.onPageRasterized.close(); | ||
98 | + _printJobs.remove(job.index); | ||
99 | + break; | ||
100 | + } | ||
101 | + } | ||
102 | + | ||
103 | + static PrintJob _newPrintJob(PrintJob job) { | ||
104 | + job.index = _jobIndex++; | ||
105 | + _printJobs[job.index] = job; | ||
106 | + return job; | ||
107 | + } | ||
108 | + | ||
109 | + @override | ||
110 | + Future<PrintingInfo> info() async { | ||
111 | + _channel.setMethodCallHandler(_handleMethod); | ||
112 | + Map<dynamic, dynamic> result; | ||
113 | + | ||
114 | + try { | ||
115 | + result = await _channel.invokeMethod( | ||
116 | + 'printingInfo', | ||
117 | + <String, dynamic>{}, | ||
118 | + ); | ||
119 | + } catch (e) { | ||
120 | + print('Error getting printing info: $e'); | ||
121 | + return PrintingInfo.unavailable; | ||
122 | + } | ||
123 | + | ||
124 | + return PrintingInfo.fromMap(result); | ||
125 | + } | ||
126 | + | ||
127 | + @override | ||
128 | + Future<bool> layoutPdf( | ||
129 | + LayoutCallback onLayout, | ||
130 | + String name, | ||
131 | + PdfPageFormat format, | ||
132 | + ) async { | ||
133 | + final PrintJob job = _newPrintJob(PrintJob( | ||
134 | + onCompleted: Completer<bool>(), | ||
135 | + onLayout: onLayout, | ||
136 | + )); | ||
137 | + | ||
138 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
139 | + 'name': name, | ||
140 | + 'job': job.index, | ||
141 | + 'width': format.width, | ||
142 | + 'height': format.height, | ||
143 | + 'marginLeft': format.marginLeft, | ||
144 | + 'marginTop': format.marginTop, | ||
145 | + 'marginRight': format.marginRight, | ||
146 | + 'marginBottom': format.marginBottom, | ||
147 | + }; | ||
148 | + | ||
149 | + await _channel.invokeMethod<int>('printPdf', params); | ||
150 | + try { | ||
151 | + return await job.onCompleted.future; | ||
152 | + } finally { | ||
153 | + _printJobs.remove(job.index); | ||
154 | + } | ||
155 | + } | ||
156 | + | ||
157 | + @override | ||
158 | + Future<Printer> pickPrinter(Rect bounds) async { | ||
159 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
160 | + 'x': bounds.left, | ||
161 | + 'y': bounds.top, | ||
162 | + 'w': bounds.width, | ||
163 | + 'h': bounds.height, | ||
164 | + }; | ||
165 | + final Map<dynamic, dynamic> printer = await _channel | ||
166 | + .invokeMethod<Map<dynamic, dynamic>>('pickPrinter', params); | ||
167 | + if (printer == null) { | ||
168 | + return null; | ||
169 | + } | ||
170 | + return Printer( | ||
171 | + url: printer['url'], | ||
172 | + name: printer['name'], | ||
173 | + model: printer['model'], | ||
174 | + location: printer['location'], | ||
175 | + ); | ||
176 | + } | ||
177 | + | ||
178 | + @override | ||
179 | + Future<bool> directPrintPdf( | ||
180 | + Printer printer, | ||
181 | + LayoutCallback onLayout, | ||
182 | + String name, | ||
183 | + PdfPageFormat format, | ||
184 | + ) async { | ||
185 | + final PrintJob job = _newPrintJob(PrintJob( | ||
186 | + onCompleted: Completer<bool>(), | ||
187 | + )); | ||
188 | + | ||
189 | + final List<int> bytes = await onLayout(format); | ||
190 | + if (bytes == null) { | ||
191 | + return false; | ||
192 | + } | ||
193 | + | ||
194 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
195 | + 'name': name, | ||
196 | + 'printer': printer.url, | ||
197 | + 'doc': Uint8List.fromList(bytes), | ||
198 | + 'job': job.index, | ||
199 | + }; | ||
200 | + await _channel.invokeMethod<int>('directPrintPdf', params); | ||
201 | + final bool result = await job.onCompleted.future; | ||
202 | + _printJobs.remove(job.index); | ||
203 | + return result; | ||
204 | + } | ||
205 | + | ||
206 | + @override | ||
207 | + Future<bool> sharePdf( | ||
208 | + List<int> bytes, | ||
209 | + String filename, | ||
210 | + Rect bounds, | ||
211 | + ) async { | ||
212 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
213 | + 'doc': Uint8List.fromList(bytes), | ||
214 | + 'name': filename, | ||
215 | + 'x': bounds.left, | ||
216 | + 'y': bounds.top, | ||
217 | + 'w': bounds.width, | ||
218 | + 'h': bounds.height, | ||
219 | + }; | ||
220 | + return await _channel.invokeMethod('sharePdf', params); | ||
221 | + } | ||
222 | + | ||
223 | + @override | ||
224 | + Future<List<int>> convertHtml( | ||
225 | + String html, String baseUrl, PdfPageFormat format) async { | ||
226 | + final PrintJob job = _newPrintJob(PrintJob( | ||
227 | + onHtmlRendered: Completer<List<int>>(), | ||
228 | + )); | ||
229 | + | ||
230 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
231 | + 'html': html, | ||
232 | + 'baseUrl': baseUrl, | ||
233 | + 'width': format.width, | ||
234 | + 'height': format.height, | ||
235 | + 'marginLeft': format.marginLeft, | ||
236 | + 'marginTop': format.marginTop, | ||
237 | + 'marginRight': format.marginRight, | ||
238 | + 'marginBottom': format.marginBottom, | ||
239 | + 'job': job.index, | ||
240 | + }; | ||
241 | + | ||
242 | + await _channel.invokeMethod<void>('convertHtml', params); | ||
243 | + final List<int> result = await job.onHtmlRendered.future; | ||
244 | + _printJobs.remove(job.index); | ||
245 | + return result; | ||
246 | + } | ||
247 | + | ||
248 | + @override | ||
249 | + Stream<PdfRaster> raster( | ||
250 | + List<int> document, | ||
251 | + List<int> pages, | ||
252 | + double dpi, | ||
253 | + ) { | ||
254 | + final PrintJob job = _newPrintJob(PrintJob( | ||
255 | + onPageRasterized: StreamController<PdfRaster>(), | ||
256 | + )); | ||
257 | + | ||
258 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
259 | + 'doc': Uint8List.fromList(document), | ||
260 | + 'pages': pages, | ||
261 | + 'scale': dpi / PdfPageFormat.inch, | ||
262 | + 'job': job.index, | ||
263 | + }; | ||
264 | + | ||
265 | + _channel.invokeMethod<void>('rasterPdf', params); | ||
266 | + return job.onPageRasterized.stream; | ||
267 | + } | ||
268 | +} |
@@ -14,10 +14,13 @@ | @@ -14,10 +14,13 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | -part of printing; | 17 | +import 'dart:async'; |
18 | 18 | ||
19 | -class _PrintJob { | ||
20 | - _PrintJob({ | 19 | +import 'callback.dart'; |
20 | +import 'raster.dart'; | ||
21 | + | ||
22 | +class PrintJob { | ||
23 | + PrintJob({ | ||
21 | this.onLayout, | 24 | this.onLayout, |
22 | this.onHtmlRendered, | 25 | this.onHtmlRendered, |
23 | this.onCompleted, | 26 | this.onCompleted, |
@@ -14,10 +14,12 @@ | @@ -14,10 +14,12 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | -part of printing; | 17 | +import 'package:meta/meta.dart'; |
18 | 18 | ||
19 | +/// Information about a printer | ||
19 | @immutable | 20 | @immutable |
20 | class Printer { | 21 | class Printer { |
22 | + /// Create a printer information | ||
21 | const Printer({ | 23 | const Printer({ |
22 | @required this.url, | 24 | @required this.url, |
23 | this.name, | 25 | this.name, |
@@ -25,9 +27,16 @@ class Printer { | @@ -25,9 +27,16 @@ class Printer { | ||
25 | this.location, | 27 | this.location, |
26 | }) : assert(url != null); | 28 | }) : assert(url != null); |
27 | 29 | ||
30 | + /// The platform specific printer identification | ||
28 | final String url; | 31 | final String url; |
32 | + | ||
33 | + /// The display name of the printer | ||
29 | final String name; | 34 | final String name; |
35 | + | ||
36 | + /// The printer model | ||
30 | final String model; | 37 | final String model; |
38 | + | ||
39 | + /// The physical location of the printer | ||
31 | final String location; | 40 | final String location; |
32 | 41 | ||
33 | @override | 42 | @override |
@@ -14,83 +14,19 @@ | @@ -14,83 +14,19 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | -part of printing; | 17 | +import 'dart:async'; |
18 | 18 | ||
19 | -typedef LayoutCallback = FutureOr<List<int>> Function(PdfPageFormat format); | 19 | +import 'package:flutter/rendering.dart' show Rect, Offset; |
20 | +import 'package:meta/meta.dart'; | ||
21 | +import 'package:pdf/pdf.dart'; | ||
20 | 22 | ||
21 | -mixin Printing { | ||
22 | - static const MethodChannel _channel = MethodChannel('net.nfet.printing'); | ||
23 | - static final Map<int, _PrintJob> _printJobs = <int, _PrintJob>{}; | ||
24 | - static int _jobIndex = 0; | ||
25 | - | ||
26 | - /// Callbacks from platform plugins | ||
27 | - static Future<dynamic> _handleMethod(MethodCall call) async { | ||
28 | - switch (call.method) { | ||
29 | - case 'onLayout': | ||
30 | - final _PrintJob job = _printJobs[call.arguments['job']]; | ||
31 | - try { | ||
32 | - final PdfPageFormat format = PdfPageFormat( | ||
33 | - call.arguments['width'], | ||
34 | - call.arguments['height'], | ||
35 | - marginLeft: call.arguments['marginLeft'], | ||
36 | - marginTop: call.arguments['marginTop'], | ||
37 | - marginRight: call.arguments['marginRight'], | ||
38 | - marginBottom: call.arguments['marginBottom'], | ||
39 | - ); | ||
40 | - | ||
41 | - final List<int> bytes = await job.onLayout(format); | ||
42 | - | ||
43 | - if (bytes == null) { | ||
44 | - return false; | ||
45 | - } | ||
46 | - | ||
47 | - return Uint8List.fromList(bytes); | ||
48 | - } catch (e) { | ||
49 | - print('Unable to print: $e'); | ||
50 | - return false; | ||
51 | - } | ||
52 | - break; | ||
53 | - case 'onCompleted': | ||
54 | - final bool completed = call.arguments['completed']; | ||
55 | - final String error = call.arguments['error']; | ||
56 | - final _PrintJob job = _printJobs[call.arguments['job']]; | ||
57 | - if (completed == false && error != null) { | ||
58 | - job.onCompleted.completeError(error); | ||
59 | - } else { | ||
60 | - job.onCompleted.complete(completed); | ||
61 | - } | ||
62 | - break; | ||
63 | - case 'onHtmlRendered': | ||
64 | - final _PrintJob job = _printJobs[call.arguments['job']]; | ||
65 | - job.onHtmlRendered.complete(call.arguments['doc']); | ||
66 | - break; | ||
67 | - case 'onHtmlError': | ||
68 | - final _PrintJob job = _printJobs[call.arguments['job']]; | ||
69 | - job.onHtmlRendered.completeError(call.arguments['error']); | ||
70 | - break; | ||
71 | - case 'onPageRasterized': | ||
72 | - final _PrintJob job = _printJobs[call.arguments['job']]; | ||
73 | - final PdfRaster raster = PdfRaster._( | ||
74 | - call.arguments['width'], | ||
75 | - call.arguments['height'], | ||
76 | - call.arguments['image'], | ||
77 | - ); | ||
78 | - job.onPageRasterized.add(raster); | ||
79 | - break; | ||
80 | - case 'onPageRasterEnd': | ||
81 | - final _PrintJob job = _printJobs[call.arguments['job']]; | ||
82 | - job.onPageRasterized.close(); | ||
83 | - _printJobs.remove(job.index); | ||
84 | - break; | ||
85 | - } | ||
86 | - } | ||
87 | - | ||
88 | - static _PrintJob _newPrintJob(_PrintJob job) { | ||
89 | - job.index = _jobIndex++; | ||
90 | - _printJobs[job.index] = job; | ||
91 | - return job; | ||
92 | - } | 23 | +import 'callback.dart'; |
24 | +import 'interface.dart'; | ||
25 | +import 'printer.dart'; | ||
26 | +import 'printing_info.dart'; | ||
27 | +import 'raster.dart'; | ||
93 | 28 | ||
29 | +mixin Printing { | ||
94 | /// Prints a Pdf document to a local printer using the platform UI | 30 | /// Prints a Pdf document to a local printer using the platform UI |
95 | /// the Pdf document is re-built in a [LayoutCallback] each time the | 31 | /// the Pdf document is re-built in a [LayoutCallback] each time the |
96 | /// user changes a setting like the page format or orientation. | 32 | /// user changes a setting like the page format or orientation. |
@@ -102,61 +38,19 @@ mixin Printing { | @@ -102,61 +38,19 @@ mixin Printing { | ||
102 | @required LayoutCallback onLayout, | 38 | @required LayoutCallback onLayout, |
103 | String name = 'Document', | 39 | String name = 'Document', |
104 | PdfPageFormat format = PdfPageFormat.standard, | 40 | PdfPageFormat format = PdfPageFormat.standard, |
105 | - }) async { | ||
106 | - _channel.setMethodCallHandler(_handleMethod); | ||
107 | - | ||
108 | - final _PrintJob job = _newPrintJob(_PrintJob( | ||
109 | - onCompleted: Completer<bool>(), | ||
110 | - onLayout: onLayout, | ||
111 | - )); | ||
112 | - | ||
113 | - final Map<String, dynamic> params = <String, dynamic>{ | ||
114 | - 'name': name, | ||
115 | - 'job': job.index, | ||
116 | - 'width': format.width, | ||
117 | - 'height': format.height, | ||
118 | - 'marginLeft': format.marginLeft, | ||
119 | - 'marginTop': format.marginTop, | ||
120 | - 'marginRight': format.marginRight, | ||
121 | - 'marginBottom': format.marginBottom, | ||
122 | - }; | 41 | + }) { |
42 | + assert(onLayout != null); | ||
43 | + assert(name != null); | ||
44 | + assert(format != null); | ||
123 | 45 | ||
124 | - await _channel.invokeMethod<int>('printPdf', params); | ||
125 | - try { | ||
126 | - return await job.onCompleted.future; | ||
127 | - } finally { | ||
128 | - _printJobs.remove(job.index); | ||
129 | - } | ||
130 | - } | ||
131 | - | ||
132 | - static Future<Map<dynamic, dynamic>> printingInfo() async { | ||
133 | - return await _channel.invokeMethod<Map<dynamic, dynamic>>( | ||
134 | - 'printingInfo', | ||
135 | - <String, dynamic>{}, | ||
136 | - ); | 46 | + return PrintingPlatform.instance.layoutPdf(onLayout, name, format); |
137 | } | 47 | } |
138 | 48 | ||
139 | /// Opens the native printer picker interface, and returns the URL of the selected printer. | 49 | /// Opens the native printer picker interface, and returns the URL of the selected printer. |
140 | - static Future<Printer> pickPrinter({Rect bounds}) async { | ||
141 | - _channel.setMethodCallHandler(_handleMethod); | 50 | + static Future<Printer> pickPrinter({Rect bounds}) { |
142 | bounds ??= Rect.fromCircle(center: Offset.zero, radius: 10); | 51 | bounds ??= Rect.fromCircle(center: Offset.zero, radius: 10); |
143 | - final Map<String, dynamic> params = <String, dynamic>{ | ||
144 | - 'x': bounds.left, | ||
145 | - 'y': bounds.top, | ||
146 | - 'w': bounds.width, | ||
147 | - 'h': bounds.height, | ||
148 | - }; | ||
149 | - final Map<dynamic, dynamic> printer = await _channel | ||
150 | - .invokeMethod<Map<dynamic, dynamic>>('pickPrinter', params); | ||
151 | - if (printer == null) { | ||
152 | - return null; | ||
153 | - } | ||
154 | - return Printer( | ||
155 | - url: printer['url'], | ||
156 | - name: printer['name'], | ||
157 | - model: printer['model'], | ||
158 | - location: printer['location'], | ||
159 | - ); | 52 | + |
53 | + return PrintingPlatform.instance.pickPrinter(bounds); | ||
160 | } | 54 | } |
161 | 55 | ||
162 | /// Prints a Pdf document to a specific local printer with no UI | 56 | /// Prints a Pdf document to a specific local printer with no UI |
@@ -164,60 +58,35 @@ mixin Printing { | @@ -164,60 +58,35 @@ mixin Printing { | ||
164 | /// returns a future with a `bool` set to true if the document is printed | 58 | /// returns a future with a `bool` set to true if the document is printed |
165 | /// and false if it is canceled. | 59 | /// and false if it is canceled. |
166 | /// throws an exception in case of error | 60 | /// throws an exception in case of error |
167 | - static Future<bool> directPrintPdf({ | 61 | + static FutureOr<bool> directPrintPdf({ |
168 | @required Printer printer, | 62 | @required Printer printer, |
169 | @required LayoutCallback onLayout, | 63 | @required LayoutCallback onLayout, |
170 | String name = 'Document', | 64 | String name = 'Document', |
171 | PdfPageFormat format = PdfPageFormat.standard, | 65 | PdfPageFormat format = PdfPageFormat.standard, |
172 | - }) async { | 66 | + }) { |
173 | if (printer == null) { | 67 | if (printer == null) { |
174 | return false; | 68 | return false; |
175 | } | 69 | } |
176 | 70 | ||
177 | - _channel.setMethodCallHandler(_handleMethod); | ||
178 | - | ||
179 | - final _PrintJob job = _newPrintJob(_PrintJob( | ||
180 | - onCompleted: Completer<bool>(), | ||
181 | - )); | ||
182 | - | ||
183 | - final List<int> bytes = await onLayout(format); | ||
184 | - if (bytes == null) { | ||
185 | - return false; | ||
186 | - } | ||
187 | - | ||
188 | - final Map<String, dynamic> params = <String, dynamic>{ | ||
189 | - 'name': name, | ||
190 | - 'printer': printer.url, | ||
191 | - 'doc': Uint8List.fromList(bytes), | ||
192 | - 'job': job.index, | ||
193 | - }; | ||
194 | - await _channel.invokeMethod<int>('directPrintPdf', params); | ||
195 | - final bool result = await job.onCompleted.future; | ||
196 | - _printJobs.remove(job.index); | ||
197 | - return result; | ||
198 | - } | ||
199 | - | ||
200 | - /// Prints a [PdfDocument] or a pdf stream to a local printer using the platform UI | ||
201 | - @Deprecated('use Printing.layoutPdf(onLayout: (_) => document.save());') | ||
202 | - static Future<void> printPdf({ | ||
203 | - @Deprecated('use bytes with document.save()') PdfDocument document, | ||
204 | - List<int> bytes, | ||
205 | - }) async { | ||
206 | - assert(document != null || bytes != null); | ||
207 | - assert(!(document == null && bytes == null)); | 71 | + assert(onLayout != null); |
72 | + assert(name != null); | ||
73 | + assert(format != null); | ||
208 | 74 | ||
209 | - layoutPdf( | ||
210 | - onLayout: (PdfPageFormat format) => | ||
211 | - document != null ? document.save() : bytes); | 75 | + return PrintingPlatform.instance.directPrintPdf( |
76 | + printer, | ||
77 | + onLayout, | ||
78 | + name, | ||
79 | + format, | ||
80 | + ); | ||
212 | } | 81 | } |
213 | 82 | ||
214 | /// Displays a platform popup to share the Pdf document to another application | 83 | /// Displays a platform popup to share the Pdf document to another application |
215 | - static Future<void> sharePdf({ | 84 | + static Future<bool> sharePdf({ |
216 | @Deprecated('use bytes with document.save()') PdfDocument document, | 85 | @Deprecated('use bytes with document.save()') PdfDocument document, |
217 | List<int> bytes, | 86 | List<int> bytes, |
218 | String filename = 'document.pdf', | 87 | String filename = 'document.pdf', |
219 | Rect bounds, | 88 | Rect bounds, |
220 | - }) async { | 89 | + }) { |
221 | assert(document != null || bytes != null); | 90 | assert(document != null || bytes != null); |
222 | assert(!(document == null && bytes == null)); | 91 | assert(!(document == null && bytes == null)); |
223 | assert(filename != null); | 92 | assert(filename != null); |
@@ -228,61 +97,40 @@ mixin Printing { | @@ -228,61 +97,40 @@ mixin Printing { | ||
228 | 97 | ||
229 | bounds ??= Rect.fromCircle(center: Offset.zero, radius: 10); | 98 | bounds ??= Rect.fromCircle(center: Offset.zero, radius: 10); |
230 | 99 | ||
231 | - final Map<String, dynamic> params = <String, dynamic>{ | ||
232 | - 'doc': Uint8List.fromList(bytes), | ||
233 | - 'name': filename, | ||
234 | - 'x': bounds.left, | ||
235 | - 'y': bounds.top, | ||
236 | - 'w': bounds.width, | ||
237 | - 'h': bounds.height, | ||
238 | - }; | ||
239 | - return await _channel.invokeMethod('sharePdf', params); | 100 | + return PrintingPlatform.instance.sharePdf( |
101 | + bytes, | ||
102 | + filename, | ||
103 | + bounds, | ||
104 | + ); | ||
240 | } | 105 | } |
241 | 106 | ||
242 | /// Convert an html document to a pdf data | 107 | /// Convert an html document to a pdf data |
243 | - static Future<List<int>> convertHtml( | ||
244 | - {@required String html, | ||
245 | - String baseUrl, | ||
246 | - PdfPageFormat format = PdfPageFormat.a4}) async { | ||
247 | - _channel.setMethodCallHandler(_handleMethod); | ||
248 | - | ||
249 | - final _PrintJob job = _newPrintJob(_PrintJob( | ||
250 | - onHtmlRendered: Completer<List<int>>(), | ||
251 | - )); | ||
252 | - | ||
253 | - final Map<String, dynamic> params = <String, dynamic>{ | ||
254 | - 'html': html, | ||
255 | - 'baseUrl': baseUrl, | ||
256 | - 'width': format.width, | ||
257 | - 'height': format.height, | ||
258 | - 'marginLeft': format.marginLeft, | ||
259 | - 'marginTop': format.marginTop, | ||
260 | - 'marginRight': format.marginRight, | ||
261 | - 'marginBottom': format.marginBottom, | ||
262 | - 'job': job.index, | ||
263 | - }; | 108 | + static Future<List<int>> convertHtml({ |
109 | + @required String html, | ||
110 | + String baseUrl, | ||
111 | + PdfPageFormat format = PdfPageFormat.standard, | ||
112 | + }) { | ||
113 | + assert(html != null); | ||
114 | + assert(format != null); | ||
264 | 115 | ||
265 | - await _channel.invokeMethod<void>('convertHtml', params); | ||
266 | - final List<int> result = await job.onHtmlRendered.future; | ||
267 | - _printJobs.remove(job.index); | ||
268 | - return result; | 116 | + return PrintingPlatform.instance.convertHtml( |
117 | + html, | ||
118 | + baseUrl, | ||
119 | + format, | ||
120 | + ); | ||
269 | } | 121 | } |
270 | 122 | ||
271 | - static Future<PrintingInfo> info() async { | ||
272 | - _channel.setMethodCallHandler(_handleMethod); | ||
273 | - Map<dynamic, dynamic> result; | ||
274 | - | ||
275 | - try { | ||
276 | - result = await _channel.invokeMethod( | ||
277 | - 'printingInfo', | ||
278 | - <String, dynamic>{}, | ||
279 | - ); | ||
280 | - } catch (e) { | ||
281 | - print('Error getting printing info: $e'); | ||
282 | - return PrintingInfo.unavailable; | ||
283 | - } | 123 | + /// Returns a [PrintingInfo] object representing the capabilities |
124 | + /// supported for the current platform | ||
125 | + static Future<PrintingInfo> info() { | ||
126 | + return PrintingPlatform.instance.info(); | ||
127 | + } | ||
284 | 128 | ||
285 | - return PrintingInfo.fromMap(result); | 129 | + /// Returns a [PrintingInfo] object representing the capabilities |
130 | + /// supported for the current platform as a map | ||
131 | + @Deprecated('Use Printing.info()') | ||
132 | + static Future<Map<dynamic, dynamic>> printingInfo() async { | ||
133 | + return (await info()).asMap(); | ||
286 | } | 134 | } |
287 | 135 | ||
288 | static Stream<PdfRaster> raster( | 136 | static Stream<PdfRaster> raster( |
@@ -290,20 +138,25 @@ mixin Printing { | @@ -290,20 +138,25 @@ mixin Printing { | ||
290 | List<int> pages, | 138 | List<int> pages, |
291 | double dpi = PdfPageFormat.inch, | 139 | double dpi = PdfPageFormat.inch, |
292 | }) { | 140 | }) { |
293 | - _channel.setMethodCallHandler(_handleMethod); | 141 | + assert(document != null); |
142 | + assert(dpi != null); | ||
143 | + assert(dpi > 0); | ||
294 | 144 | ||
295 | - final _PrintJob job = _newPrintJob(_PrintJob( | ||
296 | - onPageRasterized: StreamController<PdfRaster>(), | ||
297 | - )); | 145 | + return PrintingPlatform.instance.raster(document, pages, dpi); |
146 | + } | ||
298 | 147 | ||
299 | - final Map<String, dynamic> params = <String, dynamic>{ | ||
300 | - 'doc': Uint8List.fromList(document), | ||
301 | - 'pages': pages, | ||
302 | - 'scale': dpi / PdfPageFormat.inch, | ||
303 | - 'job': job.index, | ||
304 | - }; | 148 | + /// Prints a [PdfDocument] or a pdf stream to a local printer |
149 | + /// using the platform UI | ||
150 | + @Deprecated('use Printing.layoutPdf(onLayout: (_) => document.save());') | ||
151 | + static Future<void> printPdf({ | ||
152 | + @Deprecated('use bytes with document.save()') PdfDocument document, | ||
153 | + List<int> bytes, | ||
154 | + }) async { | ||
155 | + assert(document != null || bytes != null); | ||
156 | + assert(!(document == null && bytes == null)); | ||
305 | 157 | ||
306 | - _channel.invokeMethod<void>('rasterPdf', params); | ||
307 | - return job.onPageRasterized.stream; | 158 | + layoutPdf( |
159 | + onLayout: (PdfPageFormat format) => | ||
160 | + document != null ? document.save() : bytes); | ||
308 | } | 161 | } |
309 | } | 162 | } |
@@ -14,19 +14,10 @@ | @@ -14,19 +14,10 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | -part of printing; | ||
18 | - | 17 | +/// Capabilities supported for the current platform |
19 | class PrintingInfo { | 18 | class PrintingInfo { |
20 | - factory PrintingInfo.fromMap(Map<dynamic, dynamic> map) => PrintingInfo._( | ||
21 | - directPrint: map['directPrint'] ?? false, | ||
22 | - dynamicLayout: map['dynamicLayout'] ?? false, | ||
23 | - canPrint: map['canPrint'], | ||
24 | - canConvertHtml: map['canConvertHtml'], | ||
25 | - canShare: map['canShare'], | ||
26 | - canRaster: map['canRaster'], | ||
27 | - ); | ||
28 | - | ||
29 | - const PrintingInfo._({ | 19 | + /// Create an information object |
20 | + const PrintingInfo({ | ||
30 | this.directPrint = false, | 21 | this.directPrint = false, |
31 | this.dynamicLayout = false, | 22 | this.dynamicLayout = false, |
32 | this.canPrint = false, | 23 | this.canPrint = false, |
@@ -40,13 +31,38 @@ class PrintingInfo { | @@ -40,13 +31,38 @@ class PrintingInfo { | ||
40 | assert(canShare != null), | 31 | assert(canShare != null), |
41 | assert(canRaster != null); | 32 | assert(canRaster != null); |
42 | 33 | ||
43 | - static const PrintingInfo unavailable = PrintingInfo._(); | 34 | + /// Create an information object from a dictionnary |
35 | + factory PrintingInfo.fromMap(Map<dynamic, dynamic> map) => PrintingInfo( | ||
36 | + directPrint: map['directPrint'] ?? false, | ||
37 | + dynamicLayout: map['dynamicLayout'] ?? false, | ||
38 | + canPrint: map['canPrint'] ?? false, | ||
39 | + canConvertHtml: map['canConvertHtml'] ?? false, | ||
40 | + canShare: map['canShare'] ?? false, | ||
41 | + canRaster: map['canRaster'] ?? false, | ||
42 | + ); | ||
43 | + | ||
44 | + /// Default information with no feature available | ||
45 | + static const PrintingInfo unavailable = PrintingInfo(); | ||
44 | 46 | ||
47 | + /// The platform can print directly to a printer | ||
45 | final bool directPrint; | 48 | final bool directPrint; |
49 | + | ||
50 | + /// The platform can request a dynamic layout when the user change | ||
51 | + /// the printer or printer settings | ||
46 | final bool dynamicLayout; | 52 | final bool dynamicLayout; |
53 | + | ||
54 | + /// The platform implementation is able to print a Pdf document | ||
47 | final bool canPrint; | 55 | final bool canPrint; |
56 | + | ||
57 | + /// The platform implementation is able to convert an html document to Pdf | ||
48 | final bool canConvertHtml; | 58 | final bool canConvertHtml; |
59 | + | ||
60 | + /// The platform implementation is able to share a Pdf document | ||
61 | + /// to other applications | ||
49 | final bool canShare; | 62 | final bool canShare; |
63 | + | ||
64 | + /// The platform implementation is able to convert pages from a Pdf document | ||
65 | + /// to a stream of images | ||
50 | final bool canRaster; | 66 | final bool canRaster; |
51 | 67 | ||
52 | @override | 68 | @override |
printing/lib/src/printing_web.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +import 'dart:async'; | ||
18 | +import 'dart:convert'; | ||
19 | +import 'dart:html' as html; | ||
20 | +import 'dart:js' as js; | ||
21 | +import 'dart:typed_data'; | ||
22 | +import 'dart:ui'; | ||
23 | + | ||
24 | +import 'package:flutter/rendering.dart' show Rect; | ||
25 | +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; | ||
26 | +import 'package:pdf/pdf.dart'; | ||
27 | +import 'package:printing/src/raster.dart'; | ||
28 | +import 'package:printing/src/printer.dart'; | ||
29 | + | ||
30 | +import 'callback.dart'; | ||
31 | +import 'interface.dart'; | ||
32 | +import 'printing_info.dart'; | ||
33 | + | ||
34 | +class PrintingPlugin extends PrintingPlatform { | ||
35 | + /// Registers this class as the default instance of [PrintingPlugin]. | ||
36 | + static void registerWith(Registrar registrar) { | ||
37 | + PrintingPlatform.instance = PrintingPlugin(); | ||
38 | + } | ||
39 | + | ||
40 | + @override | ||
41 | + Future<PrintingInfo> info() async { | ||
42 | + return const PrintingInfo( | ||
43 | + directPrint: false, | ||
44 | + dynamicLayout: false, | ||
45 | + canPrint: true, | ||
46 | + canConvertHtml: false, | ||
47 | + canShare: true, | ||
48 | + ); | ||
49 | + } | ||
50 | + | ||
51 | + @override | ||
52 | + Future<bool> layoutPdf( | ||
53 | + LayoutCallback onLayout, | ||
54 | + String name, | ||
55 | + PdfPageFormat format, | ||
56 | + ) async { | ||
57 | + final List<int> result = await onLayout(format); | ||
58 | + | ||
59 | + if (result == null || result.isEmpty) { | ||
60 | + return false; | ||
61 | + } | ||
62 | + | ||
63 | + final bool isChrome = js.context['chrome'] != null; | ||
64 | + | ||
65 | + if (!isChrome) { | ||
66 | + final String pr = 'data:application/pdf;base64,${base64.encode(result)}'; | ||
67 | + final html.Window win = js.context['window']; | ||
68 | + win.open(pr, name); | ||
69 | + | ||
70 | + return true; | ||
71 | + } | ||
72 | + | ||
73 | + final Completer<bool> completer = Completer<bool>(); | ||
74 | + final html.Blob pdfFile = html.Blob( | ||
75 | + <Uint8List>[Uint8List.fromList(result)], | ||
76 | + 'application/pdf', | ||
77 | + ); | ||
78 | + final String pdfUrl = html.Url.createObjectUrl(pdfFile); | ||
79 | + final html.HtmlDocument doc = js.context['document']; | ||
80 | + final html.IFrameElement frame = doc.createElement('iframe'); | ||
81 | + frame.setAttribute( | ||
82 | + 'style', | ||
83 | + 'visibility: hidden; height: 0; width: 0; position: absolute;', | ||
84 | + // 'height: 400px; width: 600px; position: absolute; z-index: 1000', | ||
85 | + ); | ||
86 | + | ||
87 | + frame.setAttribute('src', pdfUrl); | ||
88 | + | ||
89 | + frame.addEventListener('load', (html.Event event) { | ||
90 | + final js.JsObject win = | ||
91 | + js.JsObject.fromBrowserObject(frame)['contentWindow']; | ||
92 | + | ||
93 | + win.callMethod('addEventListener', <dynamic>[ | ||
94 | + 'afterprint', | ||
95 | + js.allowInterop<html.EventListener>((html.Event event) { | ||
96 | + frame.remove(); | ||
97 | + completer.complete(true); | ||
98 | + }), | ||
99 | + ]); | ||
100 | + | ||
101 | + frame.focus(); | ||
102 | + win.callMethod('print'); | ||
103 | + }); | ||
104 | + | ||
105 | + doc.body.append(frame); | ||
106 | + | ||
107 | + return completer.future; | ||
108 | + } | ||
109 | + | ||
110 | + @override | ||
111 | + Future<bool> sharePdf( | ||
112 | + List<int> bytes, | ||
113 | + String filename, | ||
114 | + Rect bounds, | ||
115 | + ) async { | ||
116 | + final html.Blob pdfFile = html.Blob( | ||
117 | + <Uint8List>[Uint8List.fromList(bytes)], | ||
118 | + 'application/pdf', | ||
119 | + ); | ||
120 | + final String pdfUrl = html.Url.createObjectUrl(pdfFile); | ||
121 | + final html.HtmlDocument doc = js.context['document']; | ||
122 | + final html.AnchorElement link = doc.createElement('a'); | ||
123 | + link.href = pdfUrl; | ||
124 | + link.download = filename; | ||
125 | + link.click(); | ||
126 | + return true; | ||
127 | + } | ||
128 | + | ||
129 | + @override | ||
130 | + Future<List<int>> convertHtml( | ||
131 | + String html, | ||
132 | + String baseUrl, | ||
133 | + PdfPageFormat format, | ||
134 | + ) { | ||
135 | + throw UnimplementedError(); | ||
136 | + } | ||
137 | + | ||
138 | + @override | ||
139 | + Future<bool> directPrintPdf( | ||
140 | + Printer printer, | ||
141 | + LayoutCallback onLayout, | ||
142 | + String name, | ||
143 | + PdfPageFormat format, | ||
144 | + ) { | ||
145 | + throw UnimplementedError(); | ||
146 | + } | ||
147 | + | ||
148 | + @override | ||
149 | + Future<Printer> pickPrinter( | ||
150 | + Rect bounds, | ||
151 | + ) { | ||
152 | + throw UnimplementedError(); | ||
153 | + } | ||
154 | + | ||
155 | + @override | ||
156 | + Stream<PdfRaster> raster( | ||
157 | + List<int> document, | ||
158 | + List<int> pages, | ||
159 | + double dpi, | ||
160 | + ) { | ||
161 | + throw UnimplementedError(); | ||
162 | + } | ||
163 | +} |
@@ -14,17 +14,28 @@ | @@ -14,17 +14,28 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | -part of printing; | 17 | +import 'dart:async'; |
18 | +import 'dart:typed_data'; | ||
19 | +import 'dart:ui' as ui; | ||
18 | 20 | ||
21 | +import 'package:flutter/painting.dart'; | ||
22 | + | ||
23 | +/// Represents a bitmap image | ||
19 | class PdfRaster { | 24 | class PdfRaster { |
20 | - PdfRaster._( | 25 | + /// Create a bitmap image |
26 | + PdfRaster( | ||
21 | this.width, | 27 | this.width, |
22 | this.height, | 28 | this.height, |
23 | this.pixels, | 29 | this.pixels, |
24 | ); | 30 | ); |
25 | 31 | ||
32 | + /// The width of the image | ||
26 | final int width; | 33 | final int width; |
34 | + | ||
35 | + /// The height of the image | ||
27 | final int height; | 36 | final int height; |
37 | + | ||
38 | + /// The raw RGBA pixels of the image | ||
28 | final Uint8List pixels; | 39 | final Uint8List pixels; |
29 | 40 | ||
30 | @override | 41 | @override |
@@ -52,9 +63,12 @@ class PdfRaster { | @@ -52,9 +63,12 @@ class PdfRaster { | ||
52 | } | 63 | } |
53 | } | 64 | } |
54 | 65 | ||
66 | +/// Image provider for a [PdfRaster] | ||
55 | class PdfRasterImage extends ImageProvider<PdfRaster> { | 67 | class PdfRasterImage extends ImageProvider<PdfRaster> { |
68 | + /// Create an ImageProvider from a [PdfRaster] | ||
56 | PdfRasterImage(this.raster); | 69 | PdfRasterImage(this.raster); |
57 | 70 | ||
71 | + /// The image source | ||
58 | final PdfRaster raster; | 72 | final PdfRaster raster; |
59 | 73 | ||
60 | Future<ImageInfo> _loadAsync() async { | 74 | Future<ImageInfo> _loadAsync() async { |
printing/lib/src/widgets.dart
deleted
100644 → 0
1 | -/* | ||
2 | - * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | - | ||
17 | -part of printing; | ||
18 | - | ||
19 | -@Deprecated('Use `Document` instead') | ||
20 | -class PdfDoc extends Document { | ||
21 | - /// Wrapper for a [Document] with zlib compression enabled by default | ||
22 | - PdfDoc( | ||
23 | - {bool compress = true, | ||
24 | - PdfPageMode pageMode = PdfPageMode.none, | ||
25 | - Theme theme, | ||
26 | - String title, | ||
27 | - String author, | ||
28 | - String creator, | ||
29 | - String subject, | ||
30 | - String keywords, | ||
31 | - String producer}) | ||
32 | - : super( | ||
33 | - compress: compress, | ||
34 | - pageMode: pageMode, | ||
35 | - theme: theme, | ||
36 | - title: title, | ||
37 | - author: author, | ||
38 | - creator: creator, | ||
39 | - subject: subject, | ||
40 | - keywords: keywords, | ||
41 | - producer: producer, | ||
42 | - ) { | ||
43 | - Document.debug = debugPaintSizeEnabled; | ||
44 | - } | ||
45 | -} |
printing/lib/wsrc/print_job.dart
deleted
100644 → 0
1 | -/* | ||
2 | - * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | - | ||
17 | -part of printing_web; | ||
18 | - | ||
19 | -class _PrintJob { | ||
20 | - _PrintJob(this.printing, this.index); | ||
21 | - | ||
22 | - final PrintingPlugin printing; | ||
23 | - final int index; | ||
24 | - | ||
25 | - String _jobName; | ||
26 | - | ||
27 | - Future<int> printPdf( | ||
28 | - String name, | ||
29 | - double width, | ||
30 | - double height, | ||
31 | - double marginLeft, | ||
32 | - double marginTop, | ||
33 | - double marginRight, | ||
34 | - double marginBottom) async { | ||
35 | - _jobName = name; | ||
36 | - await printing.onLayout( | ||
37 | - this, width, height, marginLeft, marginTop, marginRight, marginBottom); | ||
38 | - return 1; | ||
39 | - } | ||
40 | - | ||
41 | - static Future<int> sharePdf(List<int> data, double x, double y, double width, | ||
42 | - double height, String name) async { | ||
43 | - final html.Blob pdfFile = html.Blob(<dynamic>[data], 'application/pdf'); | ||
44 | - final String pdfUrl = html.Url.createObjectUrl(pdfFile); | ||
45 | - final html.HtmlDocument doc = js.context['document']; | ||
46 | - final html.AnchorElement link = doc.createElement('a'); | ||
47 | - link.href = pdfUrl; | ||
48 | - link.download = name; | ||
49 | - link.click(); | ||
50 | - return 1; | ||
51 | - } | ||
52 | - | ||
53 | - static Map<String, dynamic> printingInfo() { | ||
54 | - return <String, dynamic>{ | ||
55 | - 'directPrint': false, | ||
56 | - 'dynamicLayout': false, | ||
57 | - 'canPrint': true, | ||
58 | - 'canConvertHtml': false, | ||
59 | - 'canShare': true, | ||
60 | - }; | ||
61 | - } | ||
62 | - | ||
63 | - void setDocument(List<int> result) { | ||
64 | - final bool isChrome = js.context['chrome'] != null; | ||
65 | - | ||
66 | - if (!isChrome) { | ||
67 | - sharePdf(result, 0, 0, 0, 0, _jobName + '.pdf'); | ||
68 | - printing.onCompleted(this, true); | ||
69 | - return; | ||
70 | - } | ||
71 | - | ||
72 | - final html.Blob pdfFile = html.Blob(<dynamic>[result], 'application/pdf'); | ||
73 | - final String pdfUrl = html.Url.createObjectUrl(pdfFile); | ||
74 | - final html.HtmlDocument doc = js.context['document']; | ||
75 | - final html.IFrameElement frame = doc.createElement('iframe'); | ||
76 | - frame.setAttribute('style', | ||
77 | - 'visibility: hidden; height: 0; width: 0; position: absolute;'); | ||
78 | - frame.setAttribute('src', pdfUrl); | ||
79 | - doc.body.append(frame); | ||
80 | - | ||
81 | - frame.addEventListener('load', (html.Event event) { | ||
82 | - final js.JsObject win = | ||
83 | - js.JsObject.fromBrowserObject(frame)['contentWindow']; | ||
84 | - | ||
85 | - win.callMethod('addEventListener', <dynamic>[ | ||
86 | - 'afterprint', | ||
87 | - js.allowInterop<html.EventListener>((html.Event event) { | ||
88 | - frame.remove(); | ||
89 | - printing.onCompleted(this, true); | ||
90 | - }), | ||
91 | - ]); | ||
92 | - | ||
93 | - frame.focus(); | ||
94 | - win.callMethod('print'); | ||
95 | - printing.onCompleted(this, true); | ||
96 | - }); | ||
97 | - } | ||
98 | - | ||
99 | - Future<void> cancelJob() async {} | ||
100 | -} |
@@ -4,7 +4,7 @@ description: Plugin that allows Flutter apps to generate and print documents to | @@ -4,7 +4,7 @@ description: Plugin that allows Flutter apps to generate and print documents to | ||
4 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/printing | 4 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/printing |
5 | repository: https://github.com/DavBfr/dart_pdf | 5 | repository: https://github.com/DavBfr/dart_pdf |
6 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues | 6 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues |
7 | -version: 3.1.0 | 7 | +version: 3.2.0 |
8 | 8 | ||
9 | environment: | 9 | environment: |
10 | sdk: ">=2.3.0 <3.0.0" | 10 | sdk: ">=2.3.0 <3.0.0" |
@@ -15,11 +15,13 @@ dependencies: | @@ -15,11 +15,13 @@ dependencies: | ||
15 | sdk: flutter | 15 | sdk: flutter |
16 | flutter_web_plugins: | 16 | flutter_web_plugins: |
17 | sdk: flutter | 17 | sdk: flutter |
18 | - pdf: "^1.3.15" | 18 | + pdf: ^1.3.15 |
19 | + plugin_platform_interface: ^1.0.2 | ||
19 | 20 | ||
20 | dev_dependencies: | 21 | dev_dependencies: |
21 | flutter_test: | 22 | flutter_test: |
22 | sdk: flutter | 23 | sdk: flutter |
24 | + mockito: ^4.1.1 | ||
23 | 25 | ||
24 | dependency_overrides: | 26 | dependency_overrides: |
25 | pdf: | 27 | pdf: |
@@ -36,5 +38,5 @@ flutter: | @@ -36,5 +38,5 @@ flutter: | ||
36 | macos: | 38 | macos: |
37 | pluginClass: PrintingPlugin | 39 | pluginClass: PrintingPlugin |
38 | web: | 40 | web: |
39 | - fileName: printing_web.dart | 41 | + fileName: src/printing_web.dart |
40 | pluginClass: PrintingPlugin | 42 | pluginClass: PrintingPlugin |
printing/test/document_test.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +import 'dart:io'; | ||
18 | +import 'dart:typed_data'; | ||
19 | + | ||
20 | +import 'package:flutter/services.dart'; | ||
21 | +import 'package:flutter/widgets.dart'; | ||
22 | +import 'package:flutter_test/flutter_test.dart'; | ||
23 | +import 'package:pdf/pdf.dart'; | ||
24 | +import 'package:pdf/widgets.dart' as pdf; | ||
25 | +import 'package:printing/printing.dart'; | ||
26 | + | ||
27 | +pdf.Document doc; | ||
28 | +pdf.Font ttf; | ||
29 | + | ||
30 | +void main() { | ||
31 | + final String path = | ||
32 | + Directory.current.path.split('/').last == 'test' ? '..' : '.'; | ||
33 | + const MethodChannel channel = MethodChannel('net.nfet.printing'); | ||
34 | + TestWidgetsFlutterBinding.ensureInitialized(); | ||
35 | + | ||
36 | + setUp(() { | ||
37 | + channel.setMockMethodCallHandler((MethodCall methodCall) async { | ||
38 | + print(methodCall); | ||
39 | + return '1'; | ||
40 | + }); | ||
41 | + }); | ||
42 | + | ||
43 | + tearDown(() { | ||
44 | + channel.setMockMethodCallHandler(null); | ||
45 | + }); | ||
46 | + | ||
47 | + test('convertHtml', () async { | ||
48 | + // expect(await Printing.platformVersion, '42'); | ||
49 | + }); | ||
50 | + | ||
51 | + test('pdfImageFromImageProvider(FileImage)', () async { | ||
52 | + final PdfImage image = await pdfImageFromImageProvider( | ||
53 | + pdf: doc.document, image: FileImage(File('$path/example.png'))); | ||
54 | + | ||
55 | + doc.addPage( | ||
56 | + pdf.Page( | ||
57 | + build: (pdf.Context context) => pdf.Center( | ||
58 | + child: pdf.Container( | ||
59 | + child: pdf.Image(image), | ||
60 | + ), | ||
61 | + ), | ||
62 | + ), | ||
63 | + ); | ||
64 | + }); | ||
65 | + | ||
66 | + setUpAll(() { | ||
67 | + pdf.Document.debug = true; | ||
68 | + pdf.RichText.debug = true; | ||
69 | + final Uint8List fontData = | ||
70 | + File('$path/../pdf/open-sans.ttf').readAsBytesSync(); | ||
71 | + ttf = pdf.Font.ttf(fontData.buffer.asByteData()); | ||
72 | + doc = pdf.Document(); | ||
73 | + }); | ||
74 | + | ||
75 | + tearDownAll(() { | ||
76 | + final File file = File('printing.pdf'); | ||
77 | + file.writeAsBytesSync(doc.save()); | ||
78 | + }); | ||
79 | +} |
printing/test/info_test.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +import 'package:flutter_test/flutter_test.dart'; | ||
18 | +import 'package:printing/printing.dart'; | ||
19 | + | ||
20 | +void main() { | ||
21 | + setUp(() { | ||
22 | + TestWidgetsFlutterBinding.ensureInitialized(); | ||
23 | + }); | ||
24 | + | ||
25 | + test('PrintingInfo', () async { | ||
26 | + final PrintingInfo info = PrintingInfo.unavailable; | ||
27 | + expect(info.canConvertHtml, false); | ||
28 | + expect(info.directPrint, false); | ||
29 | + expect(info.dynamicLayout, false); | ||
30 | + expect(info.canPrint, false); | ||
31 | + expect(info.canConvertHtml, false); | ||
32 | + expect(info.canShare, false); | ||
33 | + expect(info.canRaster, false); | ||
34 | + | ||
35 | + expect(info.toString(), isA<String>()); | ||
36 | + }); | ||
37 | + | ||
38 | + test('PrintingInfo.fromMap', () async { | ||
39 | + final PrintingInfo info = PrintingInfo.fromMap( | ||
40 | + <dynamic, dynamic>{ | ||
41 | + 'canPrint': true, | ||
42 | + }, | ||
43 | + ); | ||
44 | + | ||
45 | + expect(info.canConvertHtml, false); | ||
46 | + expect(info.directPrint, false); | ||
47 | + expect(info.dynamicLayout, false); | ||
48 | + expect(info.canPrint, true); | ||
49 | + expect(info.canConvertHtml, false); | ||
50 | + expect(info.canShare, false); | ||
51 | + expect(info.canRaster, false); | ||
52 | + }); | ||
53 | +} |
1 | -import 'dart:io'; | ||
2 | -import 'dart:typed_data'; | 1 | +/* |
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
3 | 16 | ||
4 | -import 'package:flutter/services.dart'; | ||
5 | -import 'package:flutter/widgets.dart'; | ||
6 | import 'package:flutter_test/flutter_test.dart'; | 17 | import 'package:flutter_test/flutter_test.dart'; |
18 | +import 'package:mockito/mockito.dart'; | ||
7 | import 'package:pdf/pdf.dart'; | 19 | import 'package:pdf/pdf.dart'; |
8 | -import 'package:pdf/widgets.dart' as pdf; | 20 | +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; |
9 | import 'package:printing/printing.dart'; | 21 | import 'package:printing/printing.dart'; |
10 | - | ||
11 | -pdf.Document doc; | ||
12 | -pdf.Font ttf; | 22 | +import 'package:printing/src/interface.dart'; |
13 | 23 | ||
14 | void main() { | 24 | void main() { |
15 | - final String path = | ||
16 | - Directory.current.path.split('/').last == 'test' ? '..' : '.'; | ||
17 | - const MethodChannel channel = MethodChannel('net.nfet.printing'); | ||
18 | - TestWidgetsFlutterBinding.ensureInitialized(); | ||
19 | - | ||
20 | setUp(() { | 25 | setUp(() { |
21 | - channel.setMockMethodCallHandler((MethodCall methodCall) async { | ||
22 | - print(methodCall); | ||
23 | - return '1'; | ||
24 | - }); | 26 | + TestWidgetsFlutterBinding.ensureInitialized(); |
27 | + final MockPrinting mock = MockPrinting(); | ||
28 | + PrintingPlatform.instance = mock; | ||
25 | }); | 29 | }); |
26 | 30 | ||
27 | - tearDown(() { | ||
28 | - channel.setMockMethodCallHandler(null); | 31 | + test('info', () async { |
32 | + final PrintingInfo info = await Printing.info(); | ||
33 | + expect(info, null); | ||
29 | }); | 34 | }); |
30 | 35 | ||
31 | - test('convertHtml', () async { | ||
32 | - // expect(await Printing.platformVersion, '42'); | 36 | + test('layoutPdf', () async { |
37 | + expect( | ||
38 | + () async => await Printing.layoutPdf(onLayout: null), | ||
39 | + throwsAssertionError, | ||
40 | + ); | ||
41 | + | ||
42 | + expect( | ||
43 | + await Printing.layoutPdf( | ||
44 | + onLayout: (_) => null, | ||
45 | + name: 'doc', | ||
46 | + format: PdfPageFormat.letter, | ||
47 | + ), | ||
48 | + null); | ||
33 | }); | 49 | }); |
34 | 50 | ||
35 | - test('pdfImageFromImageProvider(FileImage)', () async { | ||
36 | - final PdfImage image = await pdfImageFromImageProvider( | ||
37 | - pdf: doc.document, image: FileImage(File('$path/example.png'))); | 51 | + test('sharePdf', () async { |
52 | + expect( | ||
53 | + () async => await Printing.sharePdf(bytes: null), | ||
54 | + throwsAssertionError, | ||
55 | + ); | ||
38 | 56 | ||
39 | - doc.addPage( | ||
40 | - pdf.Page( | ||
41 | - build: (pdf.Context context) => pdf.Center( | ||
42 | - child: pdf.Container( | ||
43 | - child: pdf.Image(image), | ||
44 | - ), | ||
45 | - ), | 57 | + expect( |
58 | + await Printing.sharePdf( | ||
59 | + bytes: <int>[], | ||
60 | + ), | ||
61 | + null, | ||
62 | + ); | ||
63 | + }); | ||
64 | + | ||
65 | + test('pickPrinter', () async { | ||
66 | + expect( | ||
67 | + await Printing.pickPrinter(), | ||
68 | + null, | ||
69 | + ); | ||
70 | + }); | ||
71 | + | ||
72 | + test('directPrintPdf', () async { | ||
73 | + expect( | ||
74 | + await Printing.directPrintPdf(onLayout: null, printer: null), | ||
75 | + false, | ||
76 | + ); | ||
77 | + | ||
78 | + expect( | ||
79 | + () async => await Printing.directPrintPdf( | ||
80 | + onLayout: null, | ||
81 | + printer: const Printer(url: 'test'), | ||
82 | + ), | ||
83 | + throwsAssertionError, | ||
84 | + ); | ||
85 | + | ||
86 | + expect( | ||
87 | + await Printing.directPrintPdf( | ||
88 | + onLayout: (_) => null, | ||
89 | + printer: const Printer(url: 'test'), | ||
46 | ), | 90 | ), |
91 | + null, | ||
47 | ); | 92 | ); |
48 | }); | 93 | }); |
49 | 94 | ||
50 | - setUpAll(() { | ||
51 | - pdf.Document.debug = true; | ||
52 | - pdf.RichText.debug = true; | ||
53 | - final Uint8List fontData = | ||
54 | - File('$path/../pdf/open-sans.ttf').readAsBytesSync(); | ||
55 | - ttf = pdf.Font.ttf(fontData.buffer.asByteData()); | ||
56 | - doc = pdf.Document(); | 95 | + test('convertHtml', () async { |
96 | + expect( | ||
97 | + await Printing.convertHtml(html: '<html></html>'), | ||
98 | + null, | ||
99 | + ); | ||
57 | }); | 100 | }); |
58 | 101 | ||
59 | - tearDownAll(() { | ||
60 | - final File file = File('printing.pdf'); | ||
61 | - file.writeAsBytesSync(doc.save()); | 102 | + test('raster', () async { |
103 | + expect( | ||
104 | + () => Printing.raster(null), | ||
105 | + throwsAssertionError, | ||
106 | + ); | ||
107 | + | ||
108 | + expect( | ||
109 | + Printing.raster(<int>[]), | ||
110 | + null, | ||
111 | + ); | ||
62 | }); | 112 | }); |
63 | } | 113 | } |
114 | + | ||
115 | +class MockPrinting extends Mock | ||
116 | + with MockPlatformInterfaceMixin | ||
117 | + implements PrintingPlatform {} |
printing/test/raster_test.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +import 'dart:typed_data'; | ||
18 | +import 'dart:ui' as ui; | ||
19 | + | ||
20 | +import 'package:flutter/widgets.dart'; | ||
21 | +import 'package:flutter_test/flutter_test.dart'; | ||
22 | +import 'package:printing/printing.dart'; | ||
23 | + | ||
24 | +void main() { | ||
25 | + setUp(() { | ||
26 | + TestWidgetsFlutterBinding.ensureInitialized(); | ||
27 | + }); | ||
28 | + | ||
29 | + test('PdfRaster', () async { | ||
30 | + final PdfRaster raster = | ||
31 | + PdfRaster(10, 10, Uint8List.fromList(List<int>.filled(10 * 10 * 4, 0))); | ||
32 | + expect(raster.toString(), 'Image 10x10 400 bytes'); | ||
33 | + expect(await raster.toImage(), isA<ui.Image>()); | ||
34 | + expect(await raster.toPng(), isA<Uint8List>()); | ||
35 | + }); | ||
36 | + | ||
37 | + testWidgets('PdfRasterImage', (WidgetTester tester) async { | ||
38 | + final PdfRaster raster = | ||
39 | + PdfRaster(10, 10, Uint8List.fromList(List<int>.filled(10 * 10 * 4, 0))); | ||
40 | + | ||
41 | + await tester.pumpWidget(Image(image: PdfRasterImage(raster))); | ||
42 | + await tester.pumpAndSettle(); | ||
43 | + }); | ||
44 | +} |
-
Please register or login to post a comment