David PHAM-VAN

Improve code documentation

... ... @@ -5,6 +5,7 @@
- Add PdfPreview Widget
- Implement Printing.raster() on Flutter Web
- Fix Swift 5 deprecated function
- Improve code documentation
## 3.3.1
... ...
# Specify analysis options.
#
# Until there are meta linter rules, each desired lint must be explicitly enabled.
# See: https://github.com/dart-lang/linter/issues/288
#
# For a list of lints, see: http://dart-lang.github.io/linter/lints/
# See the configuration guide for more
# https://github.com/dart-lang/sdk/tree/master/pkg/analyzer#configuring-the-analyzer
#
# There are other similar analysis options files in the flutter repos,
# which should be kept in sync with this file:
#
# - analysis_options.yaml (this file)
# - packages/flutter/lib/analysis_options_user.yaml
# - https://github.com/flutter/plugins/blob/master/analysis_options.yaml
# - https://github.com/flutter/engine/blob/master/analysis_options.yaml
#
# This file contains the analysis options used by Flutter tools, such as IntelliJ,
# Android Studio, and the `flutter analyze` command.
include: package:pedantic/analysis_options.yaml
analyzer:
strong-mode:
implicit-dynamic: false
errors:
# treat missing required parameters as a warning (not a hint)
missing_required_param: warning
# treat missing returns as a warning (not a hint)
missing_return: warning
# allow having TODOs in the code
public_member_api_docs: warning
todo: ignore
# Ignore analyzer hints for updating pubspecs when using Future or
# Stream and not importing dart:async
# Please see https://github.com/flutter/flutter/pull/24528 for details.
sdk_version_async_exported_from_core: ignore
exclude:
- "bin/cache/**"
# the following two are relative to the stocks example and the flutter package respectively
# see https://github.com/dart-lang/sdk/issues/28463
- "lib/i18n/stock_messages_*.dart"
- "lib/src/http/**"
linter:
rules:
# these rules are documented on and in the same order as
# the Dart Lint rules page to make maintenance easier
# https://github.com/dart-lang/linter/blob/master/example/all.yaml
- always_declare_return_types
- always_put_control_body_on_new_line
# - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219
- always_require_non_null_named_parameters
- always_specify_types
- annotate_overrides
# - avoid_annotating_with_dynamic # conflicts with always_specify_types
- avoid_as
- avoid_bool_literals_in_conditional_expressions
# - avoid_catches_without_on_clauses # we do this commonly
# - avoid_catching_errors # we do this commonly
- avoid_classes_with_only_static_members
# - avoid_double_and_int_checks # only useful when targeting JS runtime
- avoid_empty_else
- avoid_field_initializers_in_const_classes
- avoid_function_literals_in_foreach_calls
# - avoid_implementing_value_types # not yet tested
- avoid_init_to_null
# - avoid_js_rounded_ints # only useful when targeting JS runtime
- avoid_null_checks_in_equality_operators
# - avoid_positional_boolean_parameters # not yet tested
# - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356)
- avoid_relative_lib_imports
- avoid_renaming_method_parameters
- avoid_return_types_on_setters
# - avoid_returning_null # there are plenty of valid reasons to return null
# - avoid_returning_null_for_future # not yet tested
- avoid_returning_null_for_void
# - avoid_returning_this # there are plenty of valid reasons to return this
# - avoid_setters_without_getters # not yet tested
# - avoid_shadowing_type_parameters # not yet tested
# - avoid_single_cascade_in_expression_statements # not yet tested
- avoid_slow_async_io
- avoid_types_as_parameter_names
# - avoid_types_on_closure_parameters # conflicts with always_specify_types
- avoid_unused_constructor_parameters
- avoid_void_async
- await_only_futures
- camel_case_types
- cancel_subscriptions
# - cascade_invocations # not yet tested
# - close_sinks # not reliable enough
# - comment_references # blocked on https://github.com/flutter/flutter/issues/20765
# - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204
- control_flow_in_finally
# - curly_braces_in_flow_control_structures # not yet tested
# - diagnostic_describe_all_properties # not yet tested
- directives_ordering
- empty_catches
- empty_constructor_bodies
- empty_statements
# - file_names # not yet tested
- flutter_style_todos
- hash_and_equals
- implementation_imports
# - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811
- iterable_contains_unrelated_type
# - join_return_with_assignment # not yet tested
- library_names
- library_prefixes
# - lines_longer_than_80_chars # not yet tested
- list_remove_unrelated_type
# - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181
- no_adjacent_strings_in_list
- no_duplicate_case_values
- non_constant_identifier_names
# - null_closures # not yet tested
# - omit_local_variable_types # opposite of always_specify_types
# - one_member_abstracts # too many false positives
# - only_throw_errors # https://github.com/flutter/flutter/issues/5792
- omit_local_variable_types
- overridden_fields
- package_api_docs
- package_names
- package_prefixed_library_names
# - parameter_assignments # we do this commonly
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
# - prefer_asserts_with_message # not yet tested
- prefer_collection_literals
- prefer_conditional_assignment
- prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
# - prefer_constructors_over_static_methods # not yet tested
- prefer_contains
# - prefer_double_quotes # opposite of prefer_single_quotes
- prefer_equal_for_default_values
# - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods
- prefer_final_fields
# - prefer_final_in_for_each # not yet tested
- prefer_final_locals
# - prefer_for_elements_to_map_fromIterable # not yet tested
- prefer_foreach
# - prefer_function_declarations_over_variables # not yet tested
- prefer_generic_function_type_aliases
- prefer_if_elements_to_conditional_expressions
- prefer_if_null_operators
- prefer_initializing_formals
- prefer_inlined_adds
# - prefer_int_literals # not yet tested
# - prefer_interpolation_to_compose_strings # not yet tested
- prefer_is_empty
- prefer_is_not_empty
- prefer_iterable_whereType
# - prefer_mixin # https://github.com/dart-lang/language/issues/32
# - prefer_null_aware_operators # disable until NNBD, see https://github.com/flutter/flutter/pull/32711#issuecomment-492930932
- prefer_single_quotes
- prefer_spread_collections
- prefer_typing_uninitialized_variables
- prefer_void_to_null
# - provide_deprecation_message # not yet tested
# - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml
- recursive_getters
- slash_for_doc_comments
# - sort_child_properties_last # not yet tested
- public_member_api_docs
- sort_constructors_first
- sort_pub_dependencies
- sort_unnamed_constructors_first
- test_types_in_equals
- throw_in_finally
# - type_annotate_public_apis # subset of always_specify_types
- type_init_formals
# - unawaited_futures # too many false positives
# - unnecessary_await_in_return # not yet tested
- unnecessary_brace_in_string_interps
- unnecessary_const
- unnecessary_getters_setters
# - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498
- unnecessary_new
- unnecessary_null_aware_assignments
- unnecessary_null_in_if_null_operators
- unnecessary_overrides
- unnecessary_parenthesis
- unnecessary_statements
- unnecessary_this
- unrelated_type_equality_checks
# - unsafe_html # not yet tested
- use_full_hex_values_for_flutter_colors
# - use_function_type_syntax_for_parameters # not yet tested
- use_rethrow_when_possible
# - use_setters_to_change_properties # not yet tested
# - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182
# - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review
- valid_regexps
# - void_checks # not yet tested
... ...
... ... @@ -15,7 +15,6 @@
*/
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/rendering.dart';
... ... @@ -28,8 +27,7 @@ import 'package:pdf/widgets.dart';
/// into a [PdfImage] instance
Future<PdfImage> pdfImageFromImage(
{@required PdfDocument pdf, @required ui.Image image}) async {
final ByteData bytes =
await image.toByteData(format: ui.ImageByteFormat.rawRgba);
final bytes = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
return PdfImage(pdf,
image: bytes.buffer.asUint8List(),
... ... @@ -44,14 +42,12 @@ Future<PdfImage> pdfImageFromImageProvider(
@required ImageProvider image,
ImageConfiguration configuration,
ImageErrorListener onError}) async {
final Completer<PdfImage> completer = Completer<PdfImage>();
final ImageStream stream =
image.resolve(configuration ?? ImageConfiguration.empty);
final completer = Completer<PdfImage>();
final stream = image.resolve(configuration ?? ImageConfiguration.empty);
ImageStreamListener listener;
listener = ImageStreamListener((ImageInfo image, bool sync) async {
final PdfImage result =
await pdfImageFromImage(pdf: pdf, image: image.image);
final result = await pdfImageFromImage(pdf: pdf, image: image.image);
if (!completer.isCompleted) {
completer.complete(result);
}
... ... @@ -75,6 +71,6 @@ Future<PdfImage> pdfImageFromImageProvider(
/// Loads a font from an asset bundle key. If used multiple times with the same font name,
/// it will be included multiple times in the pdf file
Future<TtfFont> fontFromAssetBundle(String key, AssetBundle bundle) async {
final ByteData data = await bundle.load(key);
final data = await bundle.load(key);
return TtfFont(data);
}
... ...
... ... @@ -32,6 +32,7 @@ const MethodChannel _channel = MethodChannel('net.nfet.printing');
/// An implementation of [PrintingPlatform] that uses method channels.
class MethodChannelPrinting extends PrintingPlatform {
/// Create a [PrintingPlatform] object for method channels.
MethodChannelPrinting() : super() {
_channel.setMethodCallHandler(_handleMethod);
}
... ... @@ -43,8 +44,8 @@ class MethodChannelPrinting extends PrintingPlatform {
static Future<dynamic> _handleMethod(MethodCall call) async {
switch (call.method) {
case 'onLayout':
final PrintJob job = _printJobs[call.arguments['job']];
final PdfPageFormat format = PdfPageFormat(
final job = _printJobs[call.arguments['job']];
final format = PdfPageFormat(
call.arguments['width'],
call.arguments['height'],
marginLeft: call.arguments['marginLeft'],
... ... @@ -53,7 +54,7 @@ class MethodChannelPrinting extends PrintingPlatform {
marginBottom: call.arguments['marginBottom'],
);
final Uint8List bytes = await job.onLayout(format);
final bytes = await job.onLayout(format);
if (bytes == null) {
throw 'onLayout returned null';
... ... @@ -64,7 +65,7 @@ class MethodChannelPrinting extends PrintingPlatform {
case 'onCompleted':
final bool completed = call.arguments['completed'];
final String error = call.arguments['error'];
final PrintJob job = _printJobs[call.arguments['job']];
final job = _printJobs[call.arguments['job']];
if (completed == false && error != null) {
job.onCompleted.completeError(error);
} else {
... ... @@ -72,16 +73,16 @@ class MethodChannelPrinting extends PrintingPlatform {
}
break;
case 'onHtmlRendered':
final PrintJob job = _printJobs[call.arguments['job']];
final job = _printJobs[call.arguments['job']];
job.onHtmlRendered.complete(call.arguments['doc']);
break;
case 'onHtmlError':
final PrintJob job = _printJobs[call.arguments['job']];
final job = _printJobs[call.arguments['job']];
job.onHtmlRendered.completeError(call.arguments['error']);
break;
case 'onPageRasterized':
final PrintJob job = _printJobs[call.arguments['job']];
final PdfRaster raster = PdfRaster(
final job = _printJobs[call.arguments['job']];
final raster = PdfRaster(
call.arguments['width'],
call.arguments['height'],
call.arguments['image'],
... ... @@ -89,7 +90,7 @@ class MethodChannelPrinting extends PrintingPlatform {
job.onPageRasterized.add(raster);
break;
case 'onPageRasterEnd':
final PrintJob job = _printJobs[call.arguments['job']];
final job = _printJobs[call.arguments['job']];
job.onPageRasterized.close();
_printJobs.remove(job.index);
break;
... ... @@ -126,12 +127,12 @@ class MethodChannelPrinting extends PrintingPlatform {
String name,
PdfPageFormat format,
) async {
final PrintJob job = _newPrintJob(PrintJob(
final job = _newPrintJob(PrintJob(
onCompleted: Completer<bool>(),
onLayout: onLayout,
));
final Map<String, dynamic> params = <String, dynamic>{
final params = <String, dynamic>{
'name': name,
'job': job.index,
'width': format.width,
... ... @@ -152,14 +153,14 @@ class MethodChannelPrinting extends PrintingPlatform {
@override
Future<Printer> pickPrinter(Rect bounds) async {
final Map<String, dynamic> params = <String, dynamic>{
final params = <String, dynamic>{
'x': bounds.left,
'y': bounds.top,
'w': bounds.width,
'h': bounds.height,
};
final Map<dynamic, dynamic> printer = await _channel
.invokeMethod<Map<dynamic, dynamic>>('pickPrinter', params);
final printer = await _channel.invokeMethod<Map<dynamic, dynamic>>(
'pickPrinter', params);
if (printer == null) {
return null;
}
... ... @@ -178,23 +179,23 @@ class MethodChannelPrinting extends PrintingPlatform {
String name,
PdfPageFormat format,
) async {
final PrintJob job = _newPrintJob(PrintJob(
final job = _newPrintJob(PrintJob(
onCompleted: Completer<bool>(),
));
final Uint8List bytes = await onLayout(format);
final bytes = await onLayout(format);
if (bytes == null) {
return false;
}
final Map<String, dynamic> params = <String, dynamic>{
final params = <String, dynamic>{
'name': name,
'printer': printer.url,
'doc': Uint8List.fromList(bytes),
'job': job.index,
};
await _channel.invokeMethod<int>('directPrintPdf', params);
final bool result = await job.onCompleted.future;
final result = await job.onCompleted.future;
_printJobs.remove(job.index);
return result;
}
... ... @@ -205,7 +206,7 @@ class MethodChannelPrinting extends PrintingPlatform {
String filename,
Rect bounds,
) async {
final Map<String, dynamic> params = <String, dynamic>{
final params = <String, dynamic>{
'doc': Uint8List.fromList(bytes),
'name': filename,
'x': bounds.left,
... ... @@ -219,11 +220,11 @@ class MethodChannelPrinting extends PrintingPlatform {
@override
Future<Uint8List> convertHtml(
String html, String baseUrl, PdfPageFormat format) async {
final PrintJob job = _newPrintJob(PrintJob(
final job = _newPrintJob(PrintJob(
onHtmlRendered: Completer<Uint8List>(),
));
final Map<String, dynamic> params = <String, dynamic>{
final params = <String, dynamic>{
'html': html,
'baseUrl': baseUrl,
'width': format.width,
... ... @@ -236,7 +237,7 @@ class MethodChannelPrinting extends PrintingPlatform {
};
await _channel.invokeMethod<void>('convertHtml', params);
final Uint8List result = await job.onHtmlRendered.future;
final result = await job.onHtmlRendered.future;
_printJobs.remove(job.index);
return result;
}
... ... @@ -247,11 +248,11 @@ class MethodChannelPrinting extends PrintingPlatform {
List<int> pages,
double dpi,
) {
final PrintJob job = _newPrintJob(PrintJob(
final job = _newPrintJob(PrintJob(
onPageRasterized: StreamController<PdfRaster>(),
));
final Map<String, dynamic> params = <String, dynamic>{
final params = <String, dynamic>{
'doc': Uint8List.fromList(document),
'pages': pages,
'scale': dpi / PdfPageFormat.inch,
... ...
... ... @@ -10,7 +10,9 @@ import 'printing.dart';
import 'printing_info.dart';
import 'raster.dart';
/// Flutter widget that uses the rasterized pdf pages to display a document.
class PdfPreview extends StatefulWidget {
/// Show a pdf document built on demand
const PdfPreview({
Key key,
@required this.build,
... ... @@ -26,26 +28,37 @@ class PdfPreview extends StatefulWidget {
this.onShared,
}) : super(key: key);
/// Called when a pdf document is needed
final LayoutCallback build;
/// Pdf page format asked for the first display
final PdfPageFormat initialPageFormat;
/// Add a button to print the pdf document
final bool allowPrinting;
/// Add a button to share the pdf document
final bool allowSharing;
/// Maximum width of the pdf document on screen
final double maxPageWidth;
/// Add a drop-down menu to choose the page format
final bool canChangePageFormat;
/// Additionnal actions to add to the widget
final List<PdfPreviewAction> actions;
/// List of page formats the user can choose
final Map<String, PdfPageFormat> pageFormats;
/// Called if an error creating the Pdf occured
final Widget Function(BuildContext context) onError;
/// Called if the user prints the pdf document
final void Function(BuildContext context) onPrinted;
/// Called if the user shares the pdf document
final void Function(BuildContext context) onShared;
@override
... ... @@ -93,7 +106,7 @@ class _PdfPreviewState extends State<PdfPreview> {
});
}
int pageNum = 0;
var pageNum = 0;
await for (final PdfRaster page in Printing.raster(_doc, dpi: dpi)) {
setState(() {
if (pages.length <= pageNum) {
... ... @@ -111,9 +124,9 @@ class _PdfPreviewState extends State<PdfPreview> {
@override
void initState() {
final Locale locale =
final locale =
WidgetsBinding.instance.window.locale ?? const Locale('en', 'US');
final String cc = locale.countryCode;
final cc = locale.countryCode;
if (cc == 'US' || cc == 'CA' || cc == 'MX') {
pageFormat = widget.initialPageFormat ?? PdfPageFormat.letter;
} else {
... ... @@ -150,7 +163,7 @@ class _PdfPreviewState extends State<PdfPreview> {
});
}
final MediaQueryData mq = MediaQuery.of(context);
final mq = MediaQuery.of(context);
dpi = (min(mq.size.width - 16, widget.maxPageWidth ?? double.infinity)) *
mq.devicePixelRatio /
pageFormat.width *
... ... @@ -177,7 +190,7 @@ class _PdfPreviewState extends State<PdfPreview> {
Widget _createPreview() {
if (error != null) {
Widget content = _showError();
var content = _showError();
assert(() {
print(error);
content = ErrorWidget(error);
... ... @@ -204,7 +217,7 @@ class _PdfPreviewState extends State<PdfPreview> {
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
final theme = Theme.of(context);
final Widget scrollView = Container(
decoration: BoxDecoration(
... ... @@ -224,7 +237,7 @@ class _PdfPreviewState extends State<PdfPreview> {
),
);
final List<Widget> actions = <Widget>[];
final actions = <Widget>[];
if (widget.allowPrinting && info.canPrint) {
actions.add(
... ... @@ -248,9 +261,8 @@ class _PdfPreviewState extends State<PdfPreview> {
}
if (widget.canChangePageFormat) {
final Map<String, PdfPageFormat> _pageFormats =
widget.pageFormats ?? defaultPageFormats;
final List<String> keys = _pageFormats.keys.toList();
final _pageFormats = widget.pageFormats ?? defaultPageFormats;
final keys = _pageFormats.keys.toList();
actions.add(
DropdownButton<PdfPageFormat>(
icon: Icon(
... ... @@ -261,8 +273,8 @@ class _PdfPreviewState extends State<PdfPreview> {
items: List<DropdownMenuItem<PdfPageFormat>>.generate(
_pageFormats.length,
(int index) {
final String key = keys[index];
final PdfPageFormat val = _pageFormats[key];
final key = keys[index];
final val = _pageFormats[key];
return DropdownMenuItem<PdfPageFormat>(
child: Text(key),
value: val,
... ... @@ -280,7 +292,7 @@ class _PdfPreviewState extends State<PdfPreview> {
}
if (widget.actions != null) {
for (final PdfPreviewAction action in widget.actions) {
for (final action in widget.actions) {
actions.add(
IconButton(
icon: action.icon,
... ... @@ -338,7 +350,7 @@ class _PdfPreviewState extends State<PdfPreview> {
}
Future<void> _print() async {
final bool result = await Printing.layoutPdf(onLayout: widget.build);
final result = await Printing.layoutPdf(onLayout: widget.build);
if (result && widget.onPrinted != null) {
widget.onPrinted(context);
... ... @@ -349,14 +361,14 @@ class _PdfPreviewState extends State<PdfPreview> {
// Calculate the widget center for iPad sharing popup position
final RenderBox referenceBox =
shareWidget.currentContext.findRenderObject();
final Offset topLeft =
final topLeft =
referenceBox.localToGlobal(referenceBox.paintBounds.topLeft);
final Offset bottomRight =
final bottomRight =
referenceBox.localToGlobal(referenceBox.paintBounds.bottomRight);
final Rect bounds = Rect.fromPoints(topLeft, bottomRight);
final bounds = Rect.fromPoints(topLeft, bottomRight);
final Uint8List bytes = await widget.build(pageFormat);
final bool result = await Printing.sharePdf(bytes: bytes, bounds: bounds);
final bytes = await widget.build(pageFormat);
final result = await Printing.sharePdf(bytes: bytes, bounds: bounds);
if (result && widget.onShared != null) {
widget.onShared(context);
... ... @@ -374,7 +386,7 @@ class _PdfPreviewPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final PdfRasterImage im = PdfRasterImage(page);
final im = PdfRasterImage(page);
return Container(
margin: const EdgeInsets.only(
... ... @@ -410,12 +422,17 @@ typedef OnPdfPreviewActionPressed = void Function(
PdfPageFormat pageFormat,
);
/// Action to add the the [PdfPreview] widget
class PdfPreviewAction {
/// Represents an icon to add to [PdfPreview]
const PdfPreviewAction({
@required this.icon,
@required this.onPressed,
}) : assert(icon != null);
/// The icon to display
final Icon icon;
/// The callback called when the user tap on the icon
final OnPdfPreviewActionPressed onPressed;
}
... ...
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// ignore_for_file: public_member_api_docs
@JS()
library pdf.js;
... ...
... ... @@ -20,7 +20,9 @@ import 'dart:typed_data';
import 'callback.dart';
import 'raster.dart';
/// Represents a print job to communicate with the platform implementation
class PrintJob {
/// Create a print job
PrintJob({
this.onLayout,
this.onHtmlRendered,
... ... @@ -28,10 +30,18 @@ class PrintJob {
this.onPageRasterized,
});
/// Callback used when calling Printing.layoutPdf()
final LayoutCallback onLayout;
/// Callback used when calling Printing.convertHtml()
final Completer<Uint8List> onHtmlRendered;
/// Future triggered when the job is done
final Completer<bool> onCompleted;
/// Stream of rasterized pages
final StreamController<PdfRaster> onPageRasterized;
/// The Job number
int index;
}
... ...
... ... @@ -36,6 +36,7 @@ import 'callback.dart';
import 'interface.dart';
import 'printing_info.dart';
/// Print plugin targetting Flutter on the Web
class PrintingPlugin extends PrintingPlatform {
/// Registers this class as the default instance of [PrintingPlugin].
static void registerWith(Registrar registrar) {
... ... @@ -66,35 +67,34 @@ class PrintingPlugin extends PrintingPlatform {
String name,
PdfPageFormat format,
) async {
final Uint8List result = await onLayout(format);
final result = await onLayout(format);
if (result == null || result.isEmpty) {
return false;
}
final bool isChrome = js.context['chrome'] != null;
final bool isSafari = js.context['safari'] != null;
final isChrome = js.context['chrome'] != null;
final isSafari = js.context['safari'] != null;
// Maybe Firefox 75 will support iframe printing
// https://bugzilla.mozilla.org/show_bug.cgi?id=911444
if (!isChrome && !isSafari) {
final String pr = 'data:application/pdf;base64,${base64.encode(result)}';
final pr = 'data:application/pdf;base64,${base64.encode(result)}';
final html.Window win = js.context['window'];
win.open(pr, name);
return true;
}
final Completer<bool> completer = Completer<bool>();
final html.Blob pdfFile = html.Blob(
final completer = Completer<bool>();
final pdfFile = html.Blob(
<Uint8List>[Uint8List.fromList(result)],
'application/pdf',
);
final String pdfUrl = html.Url.createObjectUrl(pdfFile);
final pdfUrl = html.Url.createObjectUrl(pdfFile);
final html.HtmlDocument doc = js.context['document'];
final html.Element frame =
doc.getElementById(_frameId) ?? doc.createElement('iframe');
final frame = doc.getElementById(_frameId) ?? doc.createElement('iframe');
frame.setAttribute(
'style',
'visibility: hidden; height: 0; width: 0; position: absolute;',
... ... @@ -126,11 +126,11 @@ class PrintingPlugin extends PrintingPlatform {
String filename,
Rect bounds,
) async {
final html.Blob pdfFile = html.Blob(
final pdfFile = html.Blob(
<Uint8List>[Uint8List.fromList(bytes)],
'application/pdf',
);
final String pdfUrl = html.Url.createObjectUrl(pdfFile);
final pdfUrl = html.Url.createObjectUrl(pdfFile);
final html.HtmlDocument doc = js.context['document'];
final html.AnchorElement link = doc.createElement('a');
link.href = pdfUrl;
... ... @@ -171,23 +171,23 @@ class PrintingPlugin extends PrintingPlatform {
List<int> pages,
double dpi,
) async* {
final PdfJsDocLoader t = PdfJs.getDocument(Settings()..data = document);
final t = PdfJs.getDocument(Settings()..data = document);
final PdfJsDoc d = await promiseToFuture(t.promise);
final int numPages = d.numPages;
final d = await promiseToFuture<PdfJsDoc>(t.promise);
final numPages = d.numPages;
final html.CanvasElement canvas =
js.context['document'].createElement('canvas');
final html.CanvasRenderingContext2D context = canvas.getContext('2d');
for (int i = 0; i < numPages; i++) {
final PdfJsPage page = await promiseToFuture(d.getPage(i + 1));
final PdfJsViewport viewport = page.getViewport(Settings()..scale = 1.5);
for (var i = 0; i < numPages; i++) {
final page = await promiseToFuture<PdfJsPage>(d.getPage(i + 1));
final viewport = page.getViewport(Settings()..scale = 1.5);
canvas.height = viewport.height.toInt();
canvas.width = viewport.width.toInt();
final Settings renderContext = Settings()
final renderContext = Settings()
..canvasContext = context
..viewport = viewport;
... ... @@ -197,10 +197,10 @@ class PrintingPlugin extends PrintingPlatform {
// context.getImageData(0, 0, canvas.width, canvas.height).data;
// Convert the image to PNG
final Completer<void> completer = Completer<void>();
final html.Blob blob = await canvas.toBlob();
final BytesBuilder data = BytesBuilder();
final html.FileReader r = FileReader();
final completer = Completer<void>();
final blob = await canvas.toBlob();
final data = BytesBuilder();
final r = FileReader();
r.readAsArrayBuffer(blob);
r.onLoadEnd.listen(
(ProgressEvent e) {
... ... @@ -233,7 +233,7 @@ class _WebPdfRaster extends PdfRaster {
@override
Uint8List get pixels {
if (_pixels == null) {
final im.Image img = asImage();
final img = asImage();
_pixels = img.data.buffer.asUint8List();
}
... ... @@ -242,7 +242,7 @@ class _WebPdfRaster extends PdfRaster {
@override
Future<Image> toImage() {
final Completer<Image> comp = Completer<Image>();
final comp = Completer<Image>();
decodeImageFromPixels(
png,
width,
... ...
... ... @@ -44,7 +44,7 @@ class PdfRaster {
/// Decode RGBA raw image to dart:ui Image
Future<ui.Image> toImage() {
final Completer<ui.Image> comp = Completer<ui.Image>();
final comp = Completer<ui.Image>();
ui.decodeImageFromPixels(
pixels,
width,
... ... @@ -57,9 +57,8 @@ class PdfRaster {
/// Convert to a PNG image
Future<Uint8List> toPng() async {
final ui.Image image = await toImage();
final ByteData data =
await image.toByteData(format: ui.ImageByteFormat.png);
final image = await toImage();
final data = await image.toByteData(format: ui.ImageByteFormat.png);
return data.buffer.asUint8List();
}
... ... @@ -78,7 +77,7 @@ class PdfRasterImage extends ImageProvider<PdfRaster> {
final PdfRaster raster;
Future<ImageInfo> _loadAsync() async {
final ui.Image uiImage = await raster.toImage();
final uiImage = await raster.toImage();
return ImageInfo(image: uiImage, scale: 1);
}
... ...
... ... @@ -15,7 +15,6 @@
*/
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
... ... @@ -35,10 +34,9 @@ Future<PdfImage> wrapWidget(
final RenderRepaintBoundary wrappedWidget =
key.currentContext.findRenderObject();
final ui.Image image = await wrappedWidget.toImage(pixelRatio: pixelRatio);
final ByteData byteData =
await image.toByteData(format: ui.ImageByteFormat.rawRgba);
final Uint8List imageData = byteData.buffer.asUint8List();
final image = await wrappedWidget.toImage(pixelRatio: pixelRatio);
final byteData = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
final imageData = byteData.buffer.asUint8List();
return PdfImage(document,
image: imageData, width: image.width, height: image.height);
}
... ...
... ... @@ -15,12 +15,10 @@
*/
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
... ... @@ -28,9 +26,8 @@ pw.Document doc;
pw.Font ttf;
void main() {
final String path =
Directory.current.path.split('/').last == 'test' ? '..' : '.';
const MethodChannel channel = MethodChannel('net.nfet.printing');
final path = Directory.current.path.split('/').last == 'test' ? '..' : '.';
const channel = MethodChannel('net.nfet.printing');
TestWidgetsFlutterBinding.ensureInitialized();
setUp(() {
... ... @@ -49,7 +46,7 @@ void main() {
});
test('pdfImageFromImageProvider(FileImage)', () async {
final PdfImage image = await pdfImageFromImageProvider(
final image = await pdfImageFromImageProvider(
pdf: doc.document, image: FileImage(File('$path/example.png')));
doc.addPage(
... ... @@ -66,14 +63,13 @@ void main() {
setUpAll(() {
pw.Document.debug = true;
pw.RichText.debug = true;
final Uint8List fontData =
File('$path/../pdf/open-sans.ttf').readAsBytesSync();
final fontData = File('$path/../pdf/open-sans.ttf').readAsBytesSync();
ttf = pw.Font.ttf(fontData.buffer.asByteData());
doc = pw.Document();
});
tearDownAll(() {
final File file = File('printing.pdf');
final file = File('printing.pdf');
file.writeAsBytesSync(doc.save());
});
}
... ...
... ... @@ -23,7 +23,7 @@ void main() {
});
test('PrintingInfo', () async {
const PrintingInfo info = PrintingInfo.unavailable;
const info = PrintingInfo.unavailable;
expect(info.canConvertHtml, false);
expect(info.directPrint, false);
expect(info.dynamicLayout, false);
... ... @@ -36,7 +36,7 @@ void main() {
});
test('PrintingInfo.fromMap', () async {
final PrintingInfo info = PrintingInfo.fromMap(
final info = PrintingInfo.fromMap(
<dynamic, dynamic>{
'canPrint': true,
},
... ...
... ... @@ -26,12 +26,12 @@ import 'package:printing/src/interface.dart';
void main() {
setUp(() {
TestWidgetsFlutterBinding.ensureInitialized();
final MockPrinting mock = MockPrinting();
final mock = MockPrinting();
PrintingPlatform.instance = mock;
});
test('info', () async {
final PrintingInfo info = await Printing.info();
final info = await Printing.info();
expect(info, null);
});
... ...
... ... @@ -27,7 +27,7 @@ void main() {
});
test('PdfRaster', () async {
final PdfRaster raster =
final raster =
PdfRaster(10, 10, Uint8List.fromList(List<int>.filled(10 * 10 * 4, 0)));
expect(raster.toString(), 'Image 10x10 400 bytes');
expect(await raster.toImage(), isA<ui.Image>());
... ... @@ -35,7 +35,7 @@ void main() {
});
testWidgets('PdfRasterImage', (WidgetTester tester) async {
final PdfRaster raster =
final raster =
PdfRaster(10, 10, Uint8List.fromList(List<int>.filled(10 * 10 * 4, 0)));
await tester.pumpWidget(Image(image: PdfRasterImage(raster)));
... ...