From b5f392ef5a69ac8d43a322c9dea65093a88195f8 Mon Sep 17 00:00:00 2001 From: Alessio Luciani Date: Thu, 4 Mar 2021 00:40:20 +0100 Subject: [PATCH 1/8] Update documentation --- lib/pdf_text.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pdf_text.dart b/lib/pdf_text.dart index 8c9c425..1ca88c8 100644 --- a/lib/pdf_text.dart +++ b/lib/pdf_text.dart @@ -10,8 +10,8 @@ const MethodChannel _CHANNEL = const MethodChannel('pdf_text'); const String _TEMP_DIR_NAME = ".flutter_pdf_text"; /// Class representing a PDF document. -/// In order to create a new [PDFDoc] instance, one of these two static methods has -/// to be used: [PDFDoc.fromFile], [PDFDoc.fromPath]. +/// In order to create a new [PDFDoc] instance, one of these static methods has +/// to be used: [PDFDoc.fromFile], [PDFDoc.fromPath], [PDFDoc.fromURL]. class PDFDoc { File _file; PDFDocInfo _info; From 78d2ef2d3eac002f0d3c8fcb589a643e48eced8f Mon Sep 17 00:00:00 2001 From: AlessioLuciani Date: Mon, 8 Mar 2021 23:46:39 +0100 Subject: [PATCH 2/8] Update dependencies for null-safety migration --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++ example/pubspec.lock | 84 ++++++++----------- lib/pdf_text.dart | 3 +- pubspec.lock | 77 ++++++++--------- pubspec.yaml | 6 +- 5 files changed, 83 insertions(+), 95 deletions(-) create mode 100644 example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/pubspec.lock b/example/pubspec.lock index e8bec5a..0703de5 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -21,7 +21,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.1" + version: "2.5.0" barcode: dependency: transitive description: @@ -35,35 +35,35 @@ packages: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.3" + version: "1.15.0" convert: dependency: transitive description: @@ -91,21 +91,21 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" ffi: dependency: transitive description: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "1.0.0" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "5.2.1" + version: "6.1.0" file_picker: dependency: "direct main" description: @@ -143,14 +143,14 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.12.2" + version: "0.13.0" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.4" + version: "4.0.0" image: dependency: transitive description: @@ -158,27 +158,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.19" - intl: - dependency: transitive - description: - name: intl - url: "https://pub.dartlang.org" - source: hosted - version: "0.16.1" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.1" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" optional: dependency: "direct dev" description: @@ -192,7 +185,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.1" + version: "1.8.0" path_parsing: dependency: transitive description: @@ -206,42 +199,42 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.6.24" + version: "2.0.1" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+2" + version: "2.0.0" path_provider_macos: dependency: transitive description: name: path_provider_macos url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+6" + version: "2.0.0" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.0" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+3" + version: "2.0.0" pdf: dependency: "direct dev" description: name: pdf url: "https://pub.dartlang.org" source: hosted - version: "1.12.0" + version: "1.13.0" pdf_text: dependency: "direct dev" description: @@ -255,7 +248,7 @@ packages: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.9.2" + version: "1.11.0" petitparser: dependency: transitive description: @@ -269,7 +262,7 @@ packages: name: platform url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "3.0.0" plugin_platform_interface: dependency: transitive description: @@ -283,7 +276,7 @@ packages: name: process url: "https://pub.dartlang.org" source: hosted - version: "3.0.13" + version: "4.1.0" qr: dependency: transitive description: @@ -302,56 +295,49 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.2" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.1" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.2" + version: "0.2.19" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" - utf: - dependency: transitive - description: - name: utf - url: "https://pub.dartlang.org" - source: hosted - version: "0.9.0+5" + version: "1.3.0" uuid: dependency: "direct dev" description: @@ -365,21 +351,21 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "1.7.4" + version: "2.0.0" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.1.2" + version: "0.2.0" xml: dependency: transitive description: @@ -388,5 +374,5 @@ packages: source: hosted version: "4.5.1" sdks: - dart: ">=2.10.0-110 <2.11.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + dart: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/lib/pdf_text.dart b/lib/pdf_text.dart index 1ca88c8..7fc9091 100644 --- a/lib/pdf_text.dart +++ b/lib/pdf_text.dart @@ -61,7 +61,8 @@ class PDFDoc { file = File(filePath); file.createSync(recursive: true); - file.writeAsBytesSync((await ClientProvider().client.get(url)).bodyBytes); + file.writeAsBytesSync( + (await ClientProvider().client.get(Uri.parse(url))).bodyBytes); } on Exception catch (e) { return Future.error(e); } diff --git a/pubspec.lock b/pubspec.lock index ed45ce0..59aa211 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,63 +7,63 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.1" + version: "2.5.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.3" + version: "1.15.0" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" ffi: dependency: transitive description: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "1.0.0" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "5.2.1" + version: "6.1.0" flutter: dependency: "direct main" description: flutter @@ -80,105 +80,98 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.12.2" + version: "0.13.0" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.4" - intl: - dependency: transitive - description: - name: intl - url: "https://pub.dartlang.org" - source: hosted - version: "0.16.1" + version: "4.0.0" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.1" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" path: dependency: "direct main" description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.1" + version: "1.8.0" path_provider: dependency: "direct main" description: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.6.24" + version: "2.0.1" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+2" + version: "2.0.0" path_provider_macos: dependency: transitive description: name: path_provider_macos url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+6" + version: "2.0.0" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+3" + version: "2.0.0" pedantic: dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.9.2" + version: "1.11.0" platform: dependency: transitive description: name: platform url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "3.0.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.0.0" process: dependency: transitive description: name: process url: "https://pub.dartlang.org" source: hosted - version: "3.0.13" + version: "4.1.0" sky_engine: dependency: transitive description: flutter @@ -190,70 +183,70 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.2" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.1" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.2" + version: "0.2.19" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "1.7.4" + version: "2.0.0" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.1.2" + version: "0.2.0" sdks: - dart: ">=2.10.0-110 <2.11.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + dart: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/pubspec.yaml b/pubspec.yaml index 7e52ed2..04bd42e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,9 +10,9 @@ environment: dependencies: flutter: sdk: flutter - path: ^1.7.0 - path_provider: ^1.6.7 - http: ^0.12.1 + path: ^1.8.0 + path_provider: ^2.0.1 + http: ^0.13.0 dev_dependencies: flutter_test: From a0d36e3ba449121ff144af0796eb4a81ae4ebac8 Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Tue, 9 Mar 2021 10:31:30 +0530 Subject: [PATCH 3/8] migrated lib and example to null-safety --- example/lib/main.dart | 25 ++--- example/pubspec.lock | 135 ++++++++++--------------- example/pubspec.yaml | 10 +- example/test/pdf_text_test.dart | 48 ++++----- example/test/utils/pdf_test_utils.dart | 16 +-- example/test/utils/test_doc_info.dart | 12 +-- example/test/utils/text_matcher.dart | 18 ++-- lib/client_provider.dart | 12 +-- lib/pdf_text.dart | 100 ++++++++++-------- pubspec.lock | 77 +++++++------- pubspec.yaml | 8 +- 11 files changed, 222 insertions(+), 239 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index ad232b0..bb2622c 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,6 +1,4 @@ -import 'dart:io'; import 'dart:math'; - import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'dart:async'; @@ -15,8 +13,8 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - PDFDoc _pdfDoc; - String _text = ""; + PDFDoc? _pdfDoc; + String? _text = ""; bool _buttonsEnabled = true; @@ -68,7 +66,7 @@ class _MyAppState extends State { child: Text( _pdfDoc == null ? "Pick a new PDF document and wait for it to load..." - : "PDF document loaded, ${_pdfDoc.length} pages\n", + : "PDF document loaded, ${_pdfDoc!.length} pages\n", style: TextStyle(fontSize: 18), textAlign: TextAlign.center, ), @@ -82,7 +80,7 @@ class _MyAppState extends State { ), padding: EdgeInsets.all(15), ), - Text(_text), + Text(_text!), ], ), )), @@ -91,9 +89,12 @@ class _MyAppState extends State { /// Picks a new PDF document from the device Future _pickPDFText() async { - File file = await FilePicker.getFile(); - _pdfDoc = await PDFDoc.fromFile(file); - setState(() {}); + // File file = await FilePicker.getFile(); + FilePickerResult? file = await FilePicker.platform.pickFiles(); + if (file?.files.first != null) { + _pdfDoc = await PDFDoc.fromPath(file!.paths.first!); + setState(() {}); + } } /// Reads a random page of the document @@ -105,8 +106,8 @@ class _MyAppState extends State { _buttonsEnabled = false; }); - String text = - await _pdfDoc.pageAt(Random().nextInt(_pdfDoc.length) + 1).text; + String? text = + await _pdfDoc!.pageAt(Random().nextInt(_pdfDoc!.length) + 1).text; setState(() { _text = text; @@ -123,7 +124,7 @@ class _MyAppState extends State { _buttonsEnabled = false; }); - String text = await _pdfDoc.text; + String text = await _pdfDoc!.text; setState(() { _text = text; diff --git a/example/pubspec.lock b/example/pubspec.lock index e8bec5a..9f0bf16 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,77 +7,63 @@ packages: name: archive url: "https://pub.dartlang.org" source: hosted - version: "2.0.13" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "1.6.0" + version: "3.1.2" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.1" + version: "2.5.0" barcode: dependency: transitive description: name: barcode url: "https://pub.dartlang.org" source: hosted - version: "1.17.1" + version: "2.1.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.3" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" + version: "1.15.0" crypto: dependency: transitive description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "3.0.0" cupertino_icons: dependency: "direct main" description: @@ -91,35 +77,28 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" ffi: dependency: transitive description: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "1.0.0" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "5.2.1" + version: "6.1.0" file_picker: dependency: "direct main" description: name: file_picker url: "https://pub.dartlang.org" source: hosted - version: "1.13.3" - file_picker_platform_interface: - dependency: transitive - description: - name: file_picker_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" + version: "3.0.0" flutter: dependency: "direct main" description: flutter @@ -131,117 +110,122 @@ packages: name: flutter_plugin_android_lifecycle url: "https://pub.dartlang.org" source: hosted - version: "1.0.11" + version: "2.0.0" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" http: dependency: transitive description: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.12.2" + version: "0.13.0" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.4" + version: "4.0.0" image: dependency: transitive description: name: image url: "https://pub.dartlang.org" source: hosted - version: "2.1.19" - intl: + version: "3.0.1" + js: dependency: transitive description: - name: intl + name: js url: "https://pub.dartlang.org" source: hosted - version: "0.16.1" + version: "0.6.3" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.1" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" optional: dependency: "direct dev" description: name: optional url: "https://pub.dartlang.org" source: hosted - version: "5.0.0+1" + version: "6.0.0-nullsafety.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.1" + version: "1.8.0" path_parsing: dependency: transitive description: name: path_parsing url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.2.0-nullsafety.0" path_provider: dependency: transitive description: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.6.24" + version: "2.0.1" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+2" + version: "2.0.0" path_provider_macos: dependency: transitive description: name: path_provider_macos url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+6" + version: "2.0.0" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.0" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+3" + version: "2.0.0" pdf: dependency: "direct dev" description: name: pdf url: "https://pub.dartlang.org" source: hosted - version: "1.12.0" + version: "3.0.1" pdf_text: dependency: "direct dev" description: @@ -255,42 +239,42 @@ packages: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.9.2" + version: "1.11.0" petitparser: dependency: transitive description: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "4.0.2" platform: dependency: transitive description: name: platform url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "3.0.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.0.0" process: dependency: transitive description: name: process url: "https://pub.dartlang.org" source: hosted - version: "3.0.13" + version: "4.1.0" qr: dependency: transitive description: name: qr url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "2.0.0" sky_engine: dependency: transitive description: flutter @@ -302,91 +286,84 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.2" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.1" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.2" + version: "0.2.19" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" - utf: - dependency: transitive - description: - name: utf - url: "https://pub.dartlang.org" - source: hosted - version: "0.9.0+5" + version: "1.3.0" uuid: dependency: "direct dev" description: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "2.2.2" + version: "3.0.1" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "1.7.4" + version: "2.0.0" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.1.2" + version: "0.2.0" xml: dependency: transitive description: name: xml url: "https://pub.dartlang.org" source: hosted - version: "4.5.1" + version: "5.0.2" sdks: - dart: ">=2.10.0-110 <2.11.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + dart: ">=2.12.0 <3.0.0" + flutter: ">=1.20.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c4998d6..4a8e772 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: 'none' version: 1.0.0+1 environment: - sdk: ">=2.3.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: flutter: @@ -14,15 +14,15 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2 - file_picker: ^1.5.0+2 + file_picker: ^3.0.0 dev_dependencies: flutter_test: sdk: flutter - pdf: ^1.12.0 - uuid: ^2.2.2 - optional: ^5.0.0+1 + pdf: ^3.0.1 + uuid: ^3.0.1 + optional: ^6.0.0-nullsafety.0 pdf_text: path: ../ diff --git a/example/test/pdf_text_test.dart b/example/test/pdf_text_test.dart index 7dc8e70..f34d842 100644 --- a/example/test/pdf_text_test.dart +++ b/example/test/pdf_text_test.dart @@ -21,13 +21,13 @@ void main() async { final testDirectoryPath = join((await getTemporaryDirectory()).path, "temp_pdf_text_dir"); - final PdfTestUtils pdfUtils = PdfTestUtils(testDirectoryPath); - final File encryptedPdf = File(join(testDirectoryPath, "encrypted.pdf")); + final PdfTestUtils pdfUtils = PdfTestUtils(testDirectoryPath); + final File encryptedPdf = File(join(testDirectoryPath, "encrypted.pdf")); setUpAll(() async { /// init mock http client so that the PDFDoc.fromUrl() obtains the mocked version ClientProvider( - client: MockClient((Request req) => Future.value(Response.bytes( + client: MockClient((Request req) => Future.value(Response.bytes( File(join(testDirectoryPath, req.url.path.split("/").last)) .readAsBytesSync(), 200)))); @@ -56,7 +56,7 @@ void main() async { subject: "The most profound theological book ever written", keywords: "Doctor,Angelicus"); - List page = [ + List page = [ "Et ut intentio nostra sub aliquibus certis limitibus comprehendatur,", "necessarium est primo investigare de ipsa sacra doctrina, qualis sit, et ad quæ se extendat.", "Circa quæ quærenda sunt decem.", @@ -65,14 +65,14 @@ void main() async { "Tertio, utrum sit una vel plures." ]; - File pdf = await pdfUtils.createPdfFile([page], info: info); + File pdf = await pdfUtils.createPdfFile([page], info: info); - PDFDoc fromFile = await PDFDoc.fromFile(pdf); - PDFDoc fromPath = await PDFDoc.fromPath(pdf.path); - PDFDoc fromUrl = + PDFDoc fromFile = await PDFDoc.fromFile(pdf); + PDFDoc fromPath = await PDFDoc.fromPath(pdf.path); + PDFDoc fromUrl = await PDFDoc.fromURL("http://localhost/${basename(pdf.path)}"); - await forEach([fromFile, fromPath, fromUrl], (doc) async { + await forEach([fromFile, fromPath, fromUrl], (dynamic doc) async { expect(await doc.text, textMatches(page)); expect(doc.pages.length, 1); expect(await doc.pages.first.text, textMatches(page)); @@ -91,27 +91,27 @@ void main() async { subject: "Detecitve stories", keywords: "Holmes,Watson"); - List page1 = [ + List page1 = [ "To Sherlock Holmes she is always the woman.", "I have seldom heard him mention her under any other name.", "In his eyes she eclipses and predominates the whole of her sex.", ]; - List page2 = [ + List page2 = [ "himself in a false position. He never spoke of the softer", "They were admirable things for the observer-excellent for", "But for the trained reasoner to admit such intrusions into", "was to introduce a distracting factor which might throw a", ]; - File pdf = await pdfUtils.createPdfFile([page1, page2], info: info); + File pdf = await pdfUtils.createPdfFile([page1, page2], info: info); - PDFDoc fromFile = await PDFDoc.fromFile(pdf); - PDFDoc fromPath = await PDFDoc.fromPath(pdf.path); - PDFDoc fromUrl = + PDFDoc fromFile = await PDFDoc.fromFile(pdf); + PDFDoc fromPath = await PDFDoc.fromPath(pdf.path); + PDFDoc fromUrl = await PDFDoc.fromURL("http://localhost/${basename(pdf.path)}"); - await forEach([fromFile, fromPath, fromUrl], (doc) async { + await forEach([fromFile, fromPath, fromUrl], (dynamic doc) async { expect(doc.pages.length, 2); expect(await doc.pageAt(1).text, textMatches(page1)); expect(await doc.pageAt(2).text, textMatches(page2)); @@ -126,17 +126,17 @@ void main() async { test("should read text from a password protected pdf file", () async { expect(encryptedPdf.existsSync(), true); - PDFDoc fromFile = + PDFDoc fromFile = await PDFDoc.fromFile(encryptedPdf, password: "password"); - PDFDoc fromPath = + PDFDoc fromPath = await PDFDoc.fromPath(encryptedPdf.path, password: "password"); - PDFDoc fromUrl = await PDFDoc.fromURL( + PDFDoc fromUrl = await PDFDoc.fromURL( "http://localhost/${basename(encryptedPdf.path)}", password: "password"); final expectedContent = "Hello World! (from an encrypted pdf document)"; - await forEach([fromFile, fromPath, fromUrl], (doc) async { + await forEach([fromFile, fromPath, fromUrl], (dynamic doc) async { expect(await doc.pageAt(1).text, textMatches([expectedContent])); expect(await doc.text, textMatches([expectedContent])); }); @@ -145,7 +145,7 @@ void main() async { test("should fail if the password is invalid", () async { expect(encryptedPdf.existsSync(), true); - int exceptionCount = 0; + int exceptionCount = 0; final fromFile = () => PDFDoc.fromFile(encryptedPdf, password: "invalid-password"); @@ -155,10 +155,10 @@ void main() async { "http://localhost/${basename(encryptedPdf.path)}", password: "invalid-password"); - await forEach([fromFile, fromPath, fromURL], (foo) async { + await forEach([fromFile, fromPath, fromURL], (dynamic foo) async { try { await foo(); - } on PlatformException catch (e) { + } on PlatformException catch (e) { expect( e.message, contains(isIos @@ -174,4 +174,4 @@ void main() async { reason: "All attempts with invalid password must fail!"); }); }); -} +} \ No newline at end of file diff --git a/example/test/utils/pdf_test_utils.dart b/example/test/utils/pdf_test_utils.dart index 478dba6..2760b73 100644 --- a/example/test/utils/pdf_test_utils.dart +++ b/example/test/utils/pdf_test_utils.dart @@ -1,5 +1,4 @@ import 'dart:io'; - import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:optional/optional.dart'; @@ -18,14 +17,14 @@ class PdfTestUtils { /// Creates a basic, single or multipage pdf document with optional info and /// saves it to a File that is subsequently returned wrapped in a Future Future createPdfFile(List> pages, - {TestDocInfo info}) async { + {TestDocInfo? info}) async { final pdf = Optional.ofNullable(info) .map((i) => pw.Document( - title: i.title, - author: i.author, - creator: i.creator, - subject: i.subject, - keywords: i.keywords)) + title: i.title!, + author: i.author!, + creator: i.creator!, + subject: i.subject!, + keywords: i.keywords!)) .orElse(pw.Document()); final pdfPages = pages @@ -42,7 +41,8 @@ class PdfTestUtils { String testFile = join(testDirectoryPath, "${Uuid().v1()}.pdf"); final file = File(testFile); - await file.writeAsBytes(pdf.save()); + + await file.writeAsBytes(await pdf.save()); return file; } } diff --git a/example/test/utils/test_doc_info.dart b/example/test/utils/test_doc_info.dart index 54032b8..9a0ce2b 100644 --- a/example/test/utils/test_doc_info.dart +++ b/example/test/utils/test_doc_info.dart @@ -1,11 +1,11 @@ import 'package:pdf_text/pdf_text.dart'; class TestDocInfo { - final String title; - final String author; - final String creator; - final String subject; - final String keywords; + final String? title; + final String? author; + final String? creator; + final String? subject; + final String? keywords; /// On the limitations and "features " of the pdf library used for creating /// test documents -> (https://github.com/DavBfr/dart_pdf) @@ -29,7 +29,7 @@ class TestDocInfo { this.author = pdfDocInfo.author, this.creator = pdfDocInfo.creator, this.subject = pdfDocInfo.subject, - this.keywords = pdfDocInfo.keywords.join(","); + this.keywords = pdfDocInfo.keywords!.join(","); @override bool operator ==(Object other) => diff --git a/example/test/utils/text_matcher.dart b/example/test/utils/text_matcher.dart index c1f8db7..561c343 100644 --- a/example/test/utils/text_matcher.dart +++ b/example/test/utils/text_matcher.dart @@ -2,27 +2,27 @@ import 'package:flutter_test/flutter_test.dart'; import 'pdf_test_utils.dart'; -Matcher textMatches(List lines) => _TextMatcher(lines); +Matcher textMatches(List lines) => _TextMatcher(lines); class _TextMatcher extends Matcher { - final List expected; + final List expected; _TextMatcher(this.expected); @override - Description describe(Description description) => description.add(_expected); + Description describe(Description description) => description.add(_expected); - String get _expected => expected.join(isIos ? " " : "\n").trim(); + String get _expected => expected.join(isIos ? " " : "\n").trim(); @override - bool matches(item, Map matchState) { - String actual = item as String; + bool matches(item, Map matchState) { + String? actual = item as String?; /// For iOS (where the PDFKit is used) positioning of new lines in the text seem not to be /// very predictable, so for the purpose of the test the \n get replaced with a single space /// in both expected (see above) and actual content and only then checked for equality. return isIos - ? actual.replaceAll(RegExp("\n"), " ").trim() == _expected - : actual.trim() == _expected; + ? actual!.replaceAll(RegExp("\n"), " ").trim() == _expected + : actual!.trim() == _expected; } -} +} \ No newline at end of file diff --git a/lib/client_provider.dart b/lib/client_provider.dart index bbb7db4..9dc49ef 100644 --- a/lib/client_provider.dart +++ b/lib/client_provider.dart @@ -1,14 +1,14 @@ import 'package:http/http.dart' show Client; class ClientProvider { - final Client _client; - static ClientProvider _instance; + final Client _client; + static ClientProvider? _instance; /// defaults to the standard dart http client - ClientProvider._create(Client client) : this._client = client ?? Client(); + ClientProvider._create(Client? client) : this._client = client ?? Client(); - factory ClientProvider({Client client}) => + factory ClientProvider({Client? client}) => _instance ?? (_instance = ClientProvider._create(client)); - Client get client => _client; -} + Client get client => _client; +} \ No newline at end of file diff --git a/lib/pdf_text.dart b/lib/pdf_text.dart index 1ca88c8..3580ad6 100644 --- a/lib/pdf_text.dart +++ b/lib/pdf_text.dart @@ -13,10 +13,10 @@ const String _TEMP_DIR_NAME = ".flutter_pdf_text"; /// In order to create a new [PDFDoc] instance, one of these static methods has /// to be used: [PDFDoc.fromFile], [PDFDoc.fromPath], [PDFDoc.fromURL]. class PDFDoc { - File _file; - PDFDocInfo _info; - List _pages; - String _password; + late File _file; + PDFDocInfo? _info; + List? _pages; + String? _password; PDFDoc._internal(); @@ -26,17 +26,18 @@ class PDFDoc { var doc = PDFDoc._internal(); doc._password = password; doc._file = file; - Map data; + Map? data; try { data = await _CHANNEL .invokeMethod('initDoc', {"path": file.path, "password": password}); } on Exception catch (e) { return Future.error(e); } - doc._pages = List(); - for (int i = 0; i < data["length"]; i++) { - doc._pages.add(PDFPage._fromDoc(doc, i)); - } + doc._pages = + List.generate(data!["length"], (index) => PDFPage._fromDoc(doc, index)); + // for (int i = 0; i < data!["length"]; i++) { + // doc._pages!.add(PDFPage._fromDoc(doc, i)); + // } doc._info = PDFDocInfo._fromMap(data["info"]); return doc; } @@ -61,7 +62,8 @@ class PDFDoc { file = File(filePath); file.createSync(recursive: true); - file.writeAsBytesSync((await ClientProvider().client.get(url)).bodyBytes); + file.writeAsBytesSync( + (await ClientProvider().client.get(Uri(path: url))).bodyBytes); } on Exception catch (e) { return Future.error(e); } @@ -69,47 +71,56 @@ class PDFDoc { } /// Gets the page of the document at the given page number. - PDFPage pageAt(int pageNumber) => _pages[pageNumber - 1]; + PDFPage pageAt(int pageNumber) => _pages![pageNumber - 1]; /// Gets the pages of this document. /// The pages indexes start at 0, but the first page has number 1. /// Therefore, if you need to access the 5th page, you will do: /// var page = doc.pages[4] /// print(page.number) -> 5 - List get pages => _pages; + List? get pages => _pages; /// Gets the number of pages of this document. - int get length => _pages.length; + int get length => _pages!.length; /// Gets the information of this document. - PDFDocInfo get info => _info; + PDFDocInfo? get info => _info; /// Gets the entire text content of the document. Future get text async { // Collecting missing pages - List missingPagesNumbers = List(); - _pages.forEach((page) { + + List missingPagesNumbers = List.generate(_pages!.length, (i) { + String? k = _pages![i]._text; + if (k != null) { + return _pages![i].number; + } + }); + + _pages!.forEach((page) { if (page._text == null) { missingPagesNumbers.add(page.number); } }); - List missingPagesTexts = List(); + + late List missingPagesTexts; // Reading missing pages, if any exists if (missingPagesNumbers.isNotEmpty) { try { missingPagesTexts = - List.from(await _CHANNEL.invokeMethod('getDocText', { + List.from(await (_CHANNEL.invokeMethod('getDocText', { "path": _file.path, "missingPagesNumbers": missingPagesNumbers, "password": _password - })); + }) as FutureOr>)); } on Exception catch (e) { return Future.error(e); } } // Populating missing pages + for (var i = 0; i < missingPagesNumbers.length; i++) { - pageAt(missingPagesNumbers[i])._text = missingPagesTexts[i]; + pageAt(missingPagesNumbers[i]!)._text = missingPagesTexts[i]; } /// Removed the \n added at the end of each page here (potentially a breaking change!). @@ -117,7 +128,7 @@ class PDFDoc { /// where it begins and where it ends, therefore there is no benefit of /// introducing an artificial page separator that is not part of the pdf /// document per se - return _pages.fold("", (pv, page) => "$pv${page._text}"); + return _pages!.fold("", (pv, page) => "$pv${page._text}"); } /// Deletes the file related to this [PDFDoc]. @@ -148,9 +159,9 @@ class PDFDoc { /// It needs not to be directly instantiated, instances will be automatically /// created by the [PDFDoc] class. class PDFPage { - PDFDoc _parentDoc; - int _number; - String _text; + late PDFDoc _parentDoc; + late int _number; + String? _text; PDFPage._fromDoc(PDFDoc parentDoc, int number) { _parentDoc = parentDoc; @@ -160,7 +171,7 @@ class PDFPage { /// Gets the text of this page. /// The text retrieval is lazy. So the text of a page is only loaded when /// it is requested for the first time. - Future get text async { + Future get text async { // Loading the text if (_text == null) { try { @@ -184,14 +195,14 @@ class PDFPage { /// It needs not to be directly instantiated, instances will be automatically /// created by the [PDFDoc] class. class PDFDocInfo { - String _author; - DateTime _creationDate; - DateTime _modificationDate; - String _creator; - String _producer; - List _keywords; - String _title; - String _subject; + String? _author; + DateTime? _creationDate; + DateTime? _modificationDate; + String? _creator; + String? _producer; + List? _keywords; + String? _title; + String? _subject; PDFDocInfo._fromMap(Map data) : this._internal( @@ -223,19 +234,20 @@ class PDFDocInfo { /// Gets the author of the document. This contains the original string of the /// authors contained in the document. Therefore there might be multiple /// authors separated by comma. Returns null if no author exists. - String get author => _author; + String? get author => _author; /// Gets the list of authors of the document. This is inferred by splitting /// the author string by comma. Returns null if no author exists. - List get authors { + List? get authors { if (author == null) { return null; } - var authorString = author.replaceAll(";", ","); + var authorString = author!.replaceAll(";", ","); authorString = authorString.replaceAll("&", ","); authorString = authorString.replaceAll("and", ","); List splitted = authorString.split(","); - List ret = List(); + List ret = []; + for (var token in splitted) { var start = 0; var end = token.length - 1; @@ -254,24 +266,24 @@ class PDFDocInfo { /// Gets the creation date of the document. Returns null if no creation /// date exists. - DateTime get creationDate => _creationDate; + DateTime? get creationDate => _creationDate; /// Gets the modification date of the document. Returns null if no /// modification date exists. - DateTime get modificationDate => _modificationDate; + DateTime? get modificationDate => _modificationDate; /// Gets the creator of the document. Returns null if no creator exists. - String get creator => _creator; + String? get creator => _creator; /// Gets the producer of the document. Returns null if no producer exists. - String get producer => _producer; + String? get producer => _producer; /// Gets the list of keywords of the document. Returns null if no keyword exists. - List get keywords => _keywords; + List? get keywords => _keywords; /// Gets the title of the document. Returns null if no title exists. - String get title => _title; + String? get title => _title; /// Gets the subject of the document. Returns null if no subject exists. - String get subject => _subject; + String? get subject => _subject; } diff --git a/pubspec.lock b/pubspec.lock index ed45ce0..19f9128 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,63 +7,63 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.1" + version: "2.5.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.3" + version: "1.15.0" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" ffi: dependency: transitive description: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "1.0.0" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "5.2.1" + version: "6.1.0" flutter: dependency: "direct main" description: flutter @@ -80,105 +80,98 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.12.2" + version: "0.13.0" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.4" - intl: - dependency: transitive - description: - name: intl - url: "https://pub.dartlang.org" - source: hosted - version: "0.16.1" + version: "4.0.0" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.1" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" path: dependency: "direct main" description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.1" + version: "1.8.0" path_provider: dependency: "direct main" description: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.6.24" + version: "2.0.1" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+2" + version: "2.0.0" path_provider_macos: dependency: transitive description: name: path_provider_macos url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+6" + version: "2.0.0" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+3" + version: "2.0.0" pedantic: dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.9.2" + version: "1.11.0" platform: dependency: transitive description: name: platform url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "3.0.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.0.0" process: dependency: transitive description: name: process url: "https://pub.dartlang.org" source: hosted - version: "3.0.13" + version: "4.1.0" sky_engine: dependency: transitive description: flutter @@ -190,70 +183,70 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.2" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.1" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.2" + version: "0.2.19" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "1.7.4" + version: "2.0.0" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.1.2" + version: "0.2.0" sdks: - dart: ">=2.10.0-110 <2.11.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + dart: ">=2.12.0 <3.0.0" + flutter: ">=1.20.0" diff --git a/pubspec.yaml b/pubspec.yaml index 7e52ed2..7dfd24a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,15 +4,15 @@ version: 0.4.0 homepage: https://github.com/AlessioLuciani/flutter-pdf-text/tree/master environment: - sdk: ">=2.3.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" flutter: ">=1.12.0" dependencies: flutter: sdk: flutter - path: ^1.7.0 - path_provider: ^1.6.7 - http: ^0.12.1 + path: ^1.8.0 + path_provider: ^2.0.1 + http: ^0.13.0 dev_dependencies: flutter_test: From 57d927255c81edafa5f97565a223085db45ec092 Mon Sep 17 00:00:00 2001 From: AlessioLuciani Date: Sun, 14 Mar 2021 22:55:10 +0100 Subject: [PATCH 4/8] Fix null-safety migration issues --- example/ios/Podfile.lock | 4 ++-- example/ios/Runner.xcodeproj/project.pbxproj | 2 -- .../project.xcworkspace/contents.xcworkspacedata | 2 +- example/lib/main.dart | 7 +++---- lib/pdf_text.dart | 14 ++++---------- 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index f2df086..866112d 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -70,7 +70,7 @@ SPEC CHECKSUMS: DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 - Flutter: 0e3d915762c693b495b44d77113d4970485de6ec + Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c pdf_text: 850e21d1a62672674099a07818c95a3f55030c81 SDWebImage: 9169792e9eec3e45bba2a0c02f74bf8bd922d1ee @@ -78,4 +78,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 3c448a1d0ade57273cab760b57b1a710ba8d268a -COCOAPODS: 1.9.3 +COCOAPODS: 1.10.0 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index de6e8fd..f1dc304 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -265,7 +265,6 @@ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework", "${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework", - "${PODS_ROOT}/../Flutter/Flutter.framework", "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", "${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework", @@ -276,7 +275,6 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework", diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a1..919434a 100644 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/example/lib/main.dart b/example/lib/main.dart index bb2622c..3848784 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -89,10 +89,9 @@ class _MyAppState extends State { /// Picks a new PDF document from the device Future _pickPDFText() async { - // File file = await FilePicker.getFile(); - FilePickerResult? file = await FilePicker.platform.pickFiles(); - if (file?.files.first != null) { - _pdfDoc = await PDFDoc.fromPath(file!.paths.first!); + var filePickerResult = await FilePicker.platform.pickFiles(); + if (filePickerResult != null) { + _pdfDoc = await PDFDoc.fromPath(filePickerResult.files.single.path!); setState(() {}); } } diff --git a/lib/pdf_text.dart b/lib/pdf_text.dart index 3580ad6..9214a3e 100644 --- a/lib/pdf_text.dart +++ b/lib/pdf_text.dart @@ -63,7 +63,7 @@ class PDFDoc { file = File(filePath); file.createSync(recursive: true); file.writeAsBytesSync( - (await ClientProvider().client.get(Uri(path: url))).bodyBytes); + (await ClientProvider().client.get(Uri.parse(url))).bodyBytes); } on Exception catch (e) { return Future.error(e); } @@ -90,13 +90,7 @@ class PDFDoc { Future get text async { // Collecting missing pages - List missingPagesNumbers = List.generate(_pages!.length, (i) { - String? k = _pages![i]._text; - if (k != null) { - return _pages![i].number; - } - }); - + List missingPagesNumbers = []; _pages!.forEach((page) { if (page._text == null) { missingPagesNumbers.add(page.number); @@ -112,7 +106,7 @@ class PDFDoc { "path": _file.path, "missingPagesNumbers": missingPagesNumbers, "password": _password - }) as FutureOr>)); + }))); } on Exception catch (e) { return Future.error(e); } @@ -120,7 +114,7 @@ class PDFDoc { // Populating missing pages for (var i = 0; i < missingPagesNumbers.length; i++) { - pageAt(missingPagesNumbers[i]!)._text = missingPagesTexts[i]; + pageAt(missingPagesNumbers[i])._text = missingPagesTexts[i]; } /// Removed the \n added at the end of each page here (potentially a breaking change!). From eeb8ac9b3f85102ed5166ae38a0c48a2e494fbb3 Mon Sep 17 00:00:00 2001 From: AlessioLuciani Date: Sun, 14 Mar 2021 23:28:26 +0100 Subject: [PATCH 5/8] Replace some nullable types with late types --- example/test/pdf_text_test.dart | 42 ++++++++++++++++----------------- lib/pdf_text.dart | 36 +++++++++++----------------- 2 files changed, 35 insertions(+), 43 deletions(-) diff --git a/example/test/pdf_text_test.dart b/example/test/pdf_text_test.dart index f34d842..b783749 100644 --- a/example/test/pdf_text_test.dart +++ b/example/test/pdf_text_test.dart @@ -1,5 +1,5 @@ @Skip( - 'To run these tests, make sure an emulator or a real device is connected, then \'cd example\' and : \'flutter run test/pfd_text_test.dart\'') + 'To run these tests, make sure an emulator or a real device is connected, then \'cd example\' and : \'flutter run test/pdf_text_test.dart\'') import 'dart:io'; import 'package:flutter/foundation.dart'; @@ -21,13 +21,13 @@ void main() async { final testDirectoryPath = join((await getTemporaryDirectory()).path, "temp_pdf_text_dir"); - final PdfTestUtils pdfUtils = PdfTestUtils(testDirectoryPath); - final File encryptedPdf = File(join(testDirectoryPath, "encrypted.pdf")); + final PdfTestUtils pdfUtils = PdfTestUtils(testDirectoryPath); + final File encryptedPdf = File(join(testDirectoryPath, "encrypted.pdf")); setUpAll(() async { /// init mock http client so that the PDFDoc.fromUrl() obtains the mocked version ClientProvider( - client: MockClient((Request req) => Future.value(Response.bytes( + client: MockClient((Request req) => Future.value(Response.bytes( File(join(testDirectoryPath, req.url.path.split("/").last)) .readAsBytesSync(), 200)))); @@ -56,7 +56,7 @@ void main() async { subject: "The most profound theological book ever written", keywords: "Doctor,Angelicus"); - List page = [ + List page = [ "Et ut intentio nostra sub aliquibus certis limitibus comprehendatur,", "necessarium est primo investigare de ipsa sacra doctrina, qualis sit, et ad quæ se extendat.", "Circa quæ quærenda sunt decem.", @@ -65,11 +65,11 @@ void main() async { "Tertio, utrum sit una vel plures." ]; - File pdf = await pdfUtils.createPdfFile([page], info: info); + File pdf = await pdfUtils.createPdfFile([page], info: info); - PDFDoc fromFile = await PDFDoc.fromFile(pdf); - PDFDoc fromPath = await PDFDoc.fromPath(pdf.path); - PDFDoc fromUrl = + PDFDoc fromFile = await PDFDoc.fromFile(pdf); + PDFDoc fromPath = await PDFDoc.fromPath(pdf.path); + PDFDoc fromUrl = await PDFDoc.fromURL("http://localhost/${basename(pdf.path)}"); await forEach([fromFile, fromPath, fromUrl], (dynamic doc) async { @@ -91,24 +91,24 @@ void main() async { subject: "Detecitve stories", keywords: "Holmes,Watson"); - List page1 = [ + List page1 = [ "To Sherlock Holmes she is always the woman.", "I have seldom heard him mention her under any other name.", "In his eyes she eclipses and predominates the whole of her sex.", ]; - List page2 = [ + List page2 = [ "himself in a false position. He never spoke of the softer", "They were admirable things for the observer-excellent for", "But for the trained reasoner to admit such intrusions into", "was to introduce a distracting factor which might throw a", ]; - File pdf = await pdfUtils.createPdfFile([page1, page2], info: info); + File pdf = await pdfUtils.createPdfFile([page1, page2], info: info); - PDFDoc fromFile = await PDFDoc.fromFile(pdf); - PDFDoc fromPath = await PDFDoc.fromPath(pdf.path); - PDFDoc fromUrl = + PDFDoc fromFile = await PDFDoc.fromFile(pdf); + PDFDoc fromPath = await PDFDoc.fromPath(pdf.path); + PDFDoc fromUrl = await PDFDoc.fromURL("http://localhost/${basename(pdf.path)}"); await forEach([fromFile, fromPath, fromUrl], (dynamic doc) async { @@ -126,11 +126,11 @@ void main() async { test("should read text from a password protected pdf file", () async { expect(encryptedPdf.existsSync(), true); - PDFDoc fromFile = + PDFDoc fromFile = await PDFDoc.fromFile(encryptedPdf, password: "password"); - PDFDoc fromPath = + PDFDoc fromPath = await PDFDoc.fromPath(encryptedPdf.path, password: "password"); - PDFDoc fromUrl = await PDFDoc.fromURL( + PDFDoc fromUrl = await PDFDoc.fromURL( "http://localhost/${basename(encryptedPdf.path)}", password: "password"); @@ -145,7 +145,7 @@ void main() async { test("should fail if the password is invalid", () async { expect(encryptedPdf.existsSync(), true); - int exceptionCount = 0; + int exceptionCount = 0; final fromFile = () => PDFDoc.fromFile(encryptedPdf, password: "invalid-password"); @@ -158,7 +158,7 @@ void main() async { await forEach([fromFile, fromPath, fromURL], (dynamic foo) async { try { await foo(); - } on PlatformException catch (e) { + } on PlatformException catch (e) { expect( e.message, contains(isIos @@ -174,4 +174,4 @@ void main() async { reason: "All attempts with invalid password must fail!"); }); }); -} \ No newline at end of file +} diff --git a/lib/pdf_text.dart b/lib/pdf_text.dart index 9214a3e..743db6e 100644 --- a/lib/pdf_text.dart +++ b/lib/pdf_text.dart @@ -14,9 +14,9 @@ const String _TEMP_DIR_NAME = ".flutter_pdf_text"; /// to be used: [PDFDoc.fromFile], [PDFDoc.fromPath], [PDFDoc.fromURL]. class PDFDoc { late File _file; - PDFDocInfo? _info; - List? _pages; - String? _password; + late PDFDocInfo _info; + late List _pages; + late String _password; PDFDoc._internal(); @@ -26,18 +26,14 @@ class PDFDoc { var doc = PDFDoc._internal(); doc._password = password; doc._file = file; - Map? data; + late Map data; try { data = await _CHANNEL .invokeMethod('initDoc', {"path": file.path, "password": password}); } on Exception catch (e) { return Future.error(e); } - doc._pages = - List.generate(data!["length"], (index) => PDFPage._fromDoc(doc, index)); - // for (int i = 0; i < data!["length"]; i++) { - // doc._pages!.add(PDFPage._fromDoc(doc, i)); - // } + doc._pages = List.generate(data["length"], (i) => PDFPage._fromDoc(doc, i)); doc._info = PDFDocInfo._fromMap(data["info"]); return doc; } @@ -71,27 +67,27 @@ class PDFDoc { } /// Gets the page of the document at the given page number. - PDFPage pageAt(int pageNumber) => _pages![pageNumber - 1]; + PDFPage pageAt(int pageNumber) => _pages[pageNumber - 1]; /// Gets the pages of this document. /// The pages indexes start at 0, but the first page has number 1. /// Therefore, if you need to access the 5th page, you will do: /// var page = doc.pages[4] /// print(page.number) -> 5 - List? get pages => _pages; + List get pages => _pages; /// Gets the number of pages of this document. - int get length => _pages!.length; + int get length => _pages.length; /// Gets the information of this document. - PDFDocInfo? get info => _info; + PDFDocInfo get info => _info; /// Gets the entire text content of the document. Future get text async { // Collecting missing pages List missingPagesNumbers = []; - _pages!.forEach((page) { + _pages.forEach((page) { if (page._text == null) { missingPagesNumbers.add(page.number); } @@ -117,12 +113,8 @@ class PDFDoc { pageAt(missingPagesNumbers[i])._text = missingPagesTexts[i]; } - /// Removed the \n added at the end of each page here (potentially a breaking change!). - /// Since every page can be retrieved individually, the client knows exactly - /// where it begins and where it ends, therefore there is no benefit of - /// introducing an artificial page separator that is not part of the pdf - /// document per se - return _pages!.fold("", (pv, page) => "$pv${page._text}"); + /// Returning the entire text, concatenating all pages + return _pages.fold("", (pv, page) => "$pv${page._text}"); } /// Deletes the file related to this [PDFDoc]. @@ -165,7 +157,7 @@ class PDFPage { /// Gets the text of this page. /// The text retrieval is lazy. So the text of a page is only loaded when /// it is requested for the first time. - Future get text async { + Future get text async { // Loading the text if (_text == null) { try { @@ -178,7 +170,7 @@ class PDFPage { return Future.error(e); } } - return _text; + return _text!; } /// Gets the page number. From 1b8dcb5fe4c467a580a407965095fe6f7fb5b9a2 Mon Sep 17 00:00:00 2001 From: AlessioLuciani Date: Sun, 14 Mar 2021 23:49:51 +0100 Subject: [PATCH 6/8] Update button widgets in example app Replacing deprecated FlatButton with TextButton. --- example/lib/main.dart | 27 +++++++++++++++------------ lib/client_provider.dart | 6 +++--- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 3848784..a4eaa61 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -14,7 +14,7 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { PDFDoc? _pdfDoc; - String? _text = ""; + String _text = ""; bool _buttonsEnabled = true; @@ -35,32 +35,35 @@ class _MyAppState extends State { padding: EdgeInsets.all(10), child: ListView( children: [ - FlatButton( + TextButton( child: Text( "Pick PDF document", style: TextStyle(color: Colors.white), ), - color: Colors.blueAccent, + style: TextButton.styleFrom( + padding: EdgeInsets.all(5), + backgroundColor: Colors.blueAccent), onPressed: _pickPDFText, - padding: EdgeInsets.all(5), ), - FlatButton( + TextButton( child: Text( "Read random page", style: TextStyle(color: Colors.white), ), - color: Colors.blueAccent, + style: TextButton.styleFrom( + padding: EdgeInsets.all(5), + backgroundColor: Colors.blueAccent), onPressed: _buttonsEnabled ? _readRandomPage : () {}, - padding: EdgeInsets.all(5), ), - FlatButton( + TextButton( child: Text( "Read whole document", style: TextStyle(color: Colors.white), ), - color: Colors.blueAccent, + style: TextButton.styleFrom( + padding: EdgeInsets.all(5), + backgroundColor: Colors.blueAccent), onPressed: _buttonsEnabled ? _readWholeDoc : () {}, - padding: EdgeInsets.all(5), ), Padding( child: Text( @@ -80,7 +83,7 @@ class _MyAppState extends State { ), padding: EdgeInsets.all(15), ), - Text(_text!), + Text(_text), ], ), )), @@ -105,7 +108,7 @@ class _MyAppState extends State { _buttonsEnabled = false; }); - String? text = + String text = await _pdfDoc!.pageAt(Random().nextInt(_pdfDoc!.length) + 1).text; setState(() { diff --git a/lib/client_provider.dart b/lib/client_provider.dart index 9dc49ef..ade3dcd 100644 --- a/lib/client_provider.dart +++ b/lib/client_provider.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart' show Client; class ClientProvider { - final Client _client; + final Client _client; static ClientProvider? _instance; /// defaults to the standard dart http client @@ -10,5 +10,5 @@ class ClientProvider { factory ClientProvider({Client? client}) => _instance ?? (_instance = ClientProvider._create(client)); - Client get client => _client; -} \ No newline at end of file + Client get client => _client; +} From 8fda051968499585bf7dfa249ff23531085c1f8b Mon Sep 17 00:00:00 2001 From: AlessioLuciani Date: Sun, 14 Mar 2021 23:58:29 +0100 Subject: [PATCH 7/8] Remove not-null cast from document info attributes in tests --- example/test/utils/pdf_test_utils.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/example/test/utils/pdf_test_utils.dart b/example/test/utils/pdf_test_utils.dart index 2760b73..0275926 100644 --- a/example/test/utils/pdf_test_utils.dart +++ b/example/test/utils/pdf_test_utils.dart @@ -20,11 +20,11 @@ class PdfTestUtils { {TestDocInfo? info}) async { final pdf = Optional.ofNullable(info) .map((i) => pw.Document( - title: i.title!, - author: i.author!, - creator: i.creator!, - subject: i.subject!, - keywords: i.keywords!)) + title: i.title, + author: i.author, + creator: i.creator, + subject: i.subject, + keywords: i.keywords)) .orElse(pw.Document()); final pdfPages = pages From 8b739ae73cc17436a6cd53d4ed0e2f5c57e02dbd Mon Sep 17 00:00:00 2001 From: AlessioLuciani Date: Mon, 15 Mar 2021 00:52:24 +0100 Subject: [PATCH 8/8] Prepare null-safety migration release --- CHANGELOG.md | 4 ++++ README.md | 3 ++- example/pubspec.lock | 2 +- example/test/utils/text_matcher.dart | 12 ++++++------ pubspec.yaml | 2 +- test/pdf_text_test.dart | 1 - 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2c8375..5f6c66a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.0 + +* Dart's sound null safety is now supported. + ## 0.4.0 * The PDFBoxResourceLoader is now used on Android to load PDF documents much faster than before. The fast initialization (i.e. *fastInit*) option has therefore been removed. diff --git a/README.md b/README.md index ffa5584..18621bd 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Add this to your package's `pubspec.yaml` file: ```yaml dependencies: - pdf_text: ^0.4.0 + pdf_text: ^0.5.0 ``` ## Usage @@ -125,6 +125,7 @@ allows you not to waste time loading text that you will probably not use. When y class PDFDoc { int length; // Number of pages of the document List pages; // Pages of the document + PDFDocInfo info; // Info of the document Future text; // Text of the document } diff --git a/example/pubspec.lock b/example/pubspec.lock index 9f0bf16..9d4f54f 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -232,7 +232,7 @@ packages: path: ".." relative: true source: path - version: "0.4.0" + version: "0.5.0" pedantic: dependency: transitive description: diff --git a/example/test/utils/text_matcher.dart b/example/test/utils/text_matcher.dart index 561c343..ab5d177 100644 --- a/example/test/utils/text_matcher.dart +++ b/example/test/utils/text_matcher.dart @@ -2,20 +2,20 @@ import 'package:flutter_test/flutter_test.dart'; import 'pdf_test_utils.dart'; -Matcher textMatches(List lines) => _TextMatcher(lines); +Matcher textMatches(List lines) => _TextMatcher(lines); class _TextMatcher extends Matcher { - final List expected; + final List expected; _TextMatcher(this.expected); @override - Description describe(Description description) => description.add(_expected); + Description describe(Description description) => description.add(_expected); - String get _expected => expected.join(isIos ? " " : "\n").trim(); + String get _expected => expected.join(isIos ? " " : "\n").trim(); @override - bool matches(item, Map matchState) { + bool matches(item, Map matchState) { String? actual = item as String?; /// For iOS (where the PDFKit is used) positioning of new lines in the text seem not to be @@ -25,4 +25,4 @@ class _TextMatcher extends Matcher { ? actual!.replaceAll(RegExp("\n"), " ").trim() == _expected : actual!.trim() == _expected; } -} \ No newline at end of file +} diff --git a/pubspec.yaml b/pubspec.yaml index 7dfd24a..4722713 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: pdf_text description: This plugin for Flutter allows you to read the text content of PDF documents and convert it into strings. It works on iOS and Android. -version: 0.4.0 +version: 0.5.0 homepage: https://github.com/AlessioLuciani/flutter-pdf-text/tree/master environment: diff --git a/test/pdf_text_test.dart b/test/pdf_text_test.dart index 3e587a9..e1f9b4a 100644 --- a/test/pdf_text_test.dart +++ b/test/pdf_text_test.dart @@ -1,6 +1,5 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:pdf_text/pdf_text.dart'; void main() { const MethodChannel channel = MethodChannel('pdf_text');