From ca3425d45bc80dcb86656401ef573cd0d9a691ec Mon Sep 17 00:00:00 2001 From: Khoren Markosyan Date: Wed, 11 May 2022 18:36:11 +0400 Subject: [PATCH] code improvements --- example/ios/Podfile.lock | 6 + example/ios/Runner/Info.plist | 2 + example/lib/pages/barcodes_page.dart | 52 ++++---- example/lib/pages/creator_page.dart | 59 +++++---- example/lib/pages/help_page.dart | 15 +++ example/lib/pages/history_page.dart | 51 ++++---- example/lib/pages/home_page.dart | 4 +- example/lib/pages/scanner_page.dart | 70 +++++------ example/lib/utils/extensions.dart | 17 ++- example/pubspec.lock | 56 ++++----- example/pubspec.yaml | 2 +- ios/Classes/src/native_zxing.cpp | 8 +- ios/Classes/src/native_zxing.h | 6 +- lib/flutter_zxing.dart | 2 +- lib/generated_bindings.dart | 4 +- lib/zxing_writer_widget.dart | 182 ++++++++++++++++++++------- 16 files changed, 340 insertions(+), 196 deletions(-) create mode 100644 example/lib/pages/help_page.dart diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 0d03d3e..7a277ce 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -12,6 +12,8 @@ PODS: - fluttertoast (0.0.2): - Flutter - Toast + - image_picker_ios (0.0.1): + - Flutter - nb_utils (0.0.1): - Flutter - path_provider_ios (0.0.1): @@ -32,6 +34,7 @@ DEPENDENCIES: - flutter_beep (from `.symlinks/plugins/flutter_beep/ios`) - flutter_zxing (from `.symlinks/plugins/flutter_zxing/ios`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - nb_utils (from `.symlinks/plugins/nb_utils/ios`) - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) @@ -56,6 +59,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_zxing/ios" fluttertoast: :path: ".symlinks/plugins/fluttertoast/ios" + image_picker_ios: + :path: ".symlinks/plugins/image_picker_ios/ios" nb_utils: :path: ".symlinks/plugins/nb_utils/ios" path_provider_ios: @@ -74,6 +79,7 @@ SPEC CHECKSUMS: flutter_beep: 54fb393b22dfa0f0e4573c81b1c74dd71c4e5af8 flutter_zxing: 19a866d17c8a87ee1026d68521c69d2f008635f6 fluttertoast: 16fbe6039d06a763f3533670197d01fc73459037 + image_picker_ios: b786a5dcf033a8336a657191401bfdf12017dabb nb_utils: ada4338858d8827ec92fdab2a545206b4ba4cfb1 path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 7d4f7c0..c704be2 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -43,6 +43,8 @@ UIViewControllerBasedStatusBarAppearance + NSPhotoLibraryUsageDescription + $(APP_DISPLAY_NAME) needs photo library access to scan barcodes NSCameraUsageDescription $(APP_DISPLAY_NAME) needs camera access to scan barcodes diff --git a/example/lib/pages/barcodes_page.dart b/example/lib/pages/barcodes_page.dart index b50624e..2dcc1e1 100644 --- a/example/lib/pages/barcodes_page.dart +++ b/example/lib/pages/barcodes_page.dart @@ -5,6 +5,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_zxing_example/models/models.dart'; import 'package:flutter_zxing_example/utils/db_service.dart'; import 'package:flutter_zxing_example/utils/router.dart'; +import 'package:flutter_zxing_example/widgets/common_widgets.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart'; @@ -49,30 +50,33 @@ class _BarcodesPageState extends State { itemCount: results.length, itemBuilder: (context, index) { final result = results[index]; - return ListTile( - leading: Image.memory(result.data ?? Uint8List(0)), - title: Text(result.text ?? ''), - subtitle: Text(result.formatName), - trailing: ButtonBar( - mainAxisSize: MainAxisSize.min, - children: [ - // Copy button - TextButton( - child: const Text('Copy'), - onPressed: () { - Clipboard.setData( - ClipboardData(text: result.text)); - }, - ), - // Remove button - IconButton( - icon: const Icon(Icons.delete, color: Colors.red), - onPressed: () { - DbService.instance.deleteEncode(result); - setState(() {}); - }, - ), - ], + return ContainerX( + child: ListTile( + leading: Image.memory(result.data ?? Uint8List(0)), + title: Text(result.text ?? ''), + subtitle: Text(result.formatName), + trailing: ButtonBar( + mainAxisSize: MainAxisSize.min, + children: [ + // Copy button + IconButton( + icon: const Icon(FontAwesomeIcons.copy), + onPressed: () { + Clipboard.setData( + ClipboardData(text: result.text)); + }, + ), + // Remove button + IconButton( + icon: const Icon(FontAwesomeIcons.trash, + color: Colors.red), + onPressed: () { + DbService.instance.deleteEncode(result); + setState(() {}); + }, + ), + ], + ), ), ); }, diff --git a/example/lib/pages/creator_page.dart b/example/lib/pages/creator_page.dart index 076b565..95c7570 100644 --- a/example/lib/pages/creator_page.dart +++ b/example/lib/pages/creator_page.dart @@ -3,8 +3,10 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_zxing/flutter_zxing.dart'; +import 'package:flutter_zxing_example/configs/constants.dart'; import 'package:flutter_zxing_example/models/encode.dart'; import 'package:flutter_zxing_example/utils/db_service.dart'; +import 'package:flutter_zxing_example/widgets/common_widgets.dart'; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; @@ -46,34 +48,36 @@ class _CreatorPageState extends State { title: const Text('Creator'), ), body: SingleChildScrollView( - child: Column( - children: [ - ZxingWriterWidget( - onSuccess: (result, bytes) { - setState(() { - encode = Encode.fromEncodeResult(result, bytes); - }); - }, - onError: (error) { - setState(() { - encode = null; - }); - ScaffoldMessenger.of(context).hideCurrentSnackBar(); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Padding( - padding: const EdgeInsets.only(bottom: 30.0), - child: Text( - error, - textAlign: TextAlign.center, + child: ContainerX( + child: Column( + children: [ + ZxingWriterWidget( + onSuccess: (result, bytes) { + setState(() { + encode = Encode.fromEncodeResult(result, bytes); + }); + }, + onError: (error) { + setState(() { + encode = null; + }); + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Padding( + padding: const EdgeInsets.only(bottom: 30.0), + child: Text( + error, + textAlign: TextAlign.center, + ), ), ), - ), - ); - }, - ), - if (encode != null) buildWriteResult(), - ], + ); + }, + ), + if (encode != null) buildWriteResult(), + ], + ), ), ), ); @@ -84,7 +88,7 @@ class _CreatorPageState extends State { children: [ // Barcode image Image.memory(encode?.data ?? Uint8List(0)), - const SizedBox(height: 20), + const SizedBox(height: spaceLarge), // Share button Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, @@ -112,6 +116,7 @@ class _CreatorPageState extends State { ), ], ), + const SizedBox(height: spaceLarge), ], ); } diff --git a/example/lib/pages/help_page.dart b/example/lib/pages/help_page.dart new file mode 100644 index 0000000..f143841 --- /dev/null +++ b/example/lib/pages/help_page.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + const HelpPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Help'), + ), + body: Container(), + ); + } +} diff --git a/example/lib/pages/history_page.dart b/example/lib/pages/history_page.dart index 4e7ca2d..7d98518 100644 --- a/example/lib/pages/history_page.dart +++ b/example/lib/pages/history_page.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_zxing_example/models/code.dart'; import 'package:flutter_zxing_example/utils/db_service.dart'; +import 'package:flutter_zxing_example/widgets/common_widgets.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart'; class HistoryPage extends StatefulWidget { @@ -39,29 +41,32 @@ class _HistoryPageState extends State { itemCount: results.length, itemBuilder: (context, index) { final result = results[index]; - return ListTile( - title: Text(result.text ?? ''), - subtitle: Text(result.formatName), - trailing: ButtonBar( - mainAxisSize: MainAxisSize.min, - children: [ - // Copy button - TextButton( - child: const Text('Copy'), - onPressed: () { - Clipboard.setData( - ClipboardData(text: result.text)); - }, - ), - // Remove button - IconButton( - icon: const Icon(Icons.delete, color: Colors.red), - onPressed: () { - DbService.instance.deleteCode(result); - setState(() {}); - }, - ), - ], + return ContainerX( + child: ListTile( + title: Text(result.text ?? ''), + subtitle: Text(result.formatName), + trailing: ButtonBar( + mainAxisSize: MainAxisSize.min, + children: [ + // Copy button + IconButton( + icon: const Icon(FontAwesomeIcons.copy), + onPressed: () { + Clipboard.setData( + ClipboardData(text: result.text)); + }, + ), + // Remove button + IconButton( + icon: const Icon(FontAwesomeIcons.trash, + color: Colors.red), + onPressed: () { + DbService.instance.deleteCode(result); + setState(() {}); + }, + ), + ], + ), ), ); }, diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart index 62886db..7240a45 100644 --- a/example/lib/pages/home_page.dart +++ b/example/lib/pages/home_page.dart @@ -1,7 +1,7 @@ import 'package:convex_bottom_bar/convex_bottom_bar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_zxing_example/pages/barcodes_page.dart'; -import 'package:flutter_zxing_example/pages/creator_page.dart'; +import 'package:flutter_zxing_example/pages/help_page.dart'; import 'package:flutter_zxing_example/pages/history_page.dart'; import 'package:flutter_zxing_example/pages/scanner_page.dart'; import 'package:flutter_zxing_example/pages/settings_page.dart'; @@ -20,7 +20,7 @@ class _HomePageState extends State { final barcodesPage = const BarcodesPage(); final historyPage = const HistoryPage(); final scannerPage = const ScannerPage(); - final helpPage = Container(); + final helpPage = const HelpPage(); final settingsPage = const SettingsPage(); dynamic pages() => [ diff --git a/example/lib/pages/scanner_page.dart b/example/lib/pages/scanner_page.dart index bca218d..19ba5b2 100644 --- a/example/lib/pages/scanner_page.dart +++ b/example/lib/pages/scanner_page.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_zxing/flutter_zxing.dart'; import 'package:flutter_zxing_example/models/models.dart'; import 'package:flutter_zxing_example/utils/db_service.dart'; +import 'package:flutter_zxing_example/utils/extensions.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:image_picker/image_picker.dart'; import 'package:image/image.dart' as imglib; @@ -33,47 +34,46 @@ class _ScannerPageState extends State { ), floatingActionButton: FloatingActionButton( child: const Icon(FontAwesomeIcons.image), - onPressed: () async { - final XFile? file = - await _picker.pickImage(source: ImageSource.gallery); - if (file != null) { - final Uint8List bytes = await file.readAsBytes(); - imglib.Image? image = imglib.decodeImage(bytes); - if (image != null) { - final CodeResult result = FlutterZxing.readBarcode( - image.getBytes(format: imglib.Format.luminance), - Format.Any, - image.width, - image.height, - 0, - 0, - ); - if (result.isValidBool) { - addCode(result); - } - } - } - }, + onPressed: pickImage, ), ); } + pickImage() async { + try { + final XFile? file = await _picker.pickImage(source: ImageSource.gallery); + if (file != null) { + readCodeFromImage(file); + } + } catch (e) { + debugPrint(e.toString()); + context.showToast(e.toString()); + } + } + + readCodeFromImage(XFile file) async { + final Uint8List bytes = await file.readAsBytes(); + imglib.Image? image = imglib.decodeImage(bytes); + if (image != null) { + final CodeResult result = FlutterZxing.readBarcode( + image.getBytes(format: imglib.Format.luminance), + Format.Any, + image.width, + image.height, + 0, + 0, + ); + if (result.isValidBool) { + addCode(result); + } else { + context.showToast('No code found'); + } + } + } + void addCode(CodeResult result) { Code code = Code.fromCodeResult(result); DbService.instance.addCode(code); - - // show snackbar - ScaffoldMessenger.of(context).hideCurrentSnackBar(); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Padding( - padding: const EdgeInsets.only(bottom: 30.0), - child: Text( - code.text ?? '', - textAlign: TextAlign.center, - ), - ), - ), - ); + context.showToast('Code added:\n${code.text ?? ''}'); } } diff --git a/example/lib/utils/extensions.dart b/example/lib/utils/extensions.dart index d5eefb4..afc2879 100644 --- a/example/lib/utils/extensions.dart +++ b/example/lib/utils/extensions.dart @@ -1,4 +1,4 @@ -import 'dart:ui'; +import 'package:flutter/material.dart'; extension LocaleParsing on String { Locale parseLocale() { @@ -46,3 +46,18 @@ extension LocaleParsing on String { return split('_').first; } } + +// context extension to show a toast message +extension ContextExtension on BuildContext { + void showToast(String message) { + ScaffoldMessenger.of(this).hideCurrentSnackBar(); + ScaffoldMessenger.of(this).showSnackBar( + SnackBar( + content: Padding( + padding: const EdgeInsets.only(bottom: 30.0), + child: Text(message, textAlign: TextAlign.center), + ), + ), + ); + } +} diff --git a/example/pubspec.lock b/example/pubspec.lock index ac7926c..d9411df 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -98,14 +98,14 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.2.3" + version: "8.3.0" camera: dependency: transitive description: name: camera url: "https://pub.dartlang.org" source: hosted - version: "0.9.4+21" + version: "0.9.4+22" camera_platform_interface: dependency: transitive description: @@ -119,7 +119,7 @@ packages: name: camera_web url: "https://pub.dartlang.org" source: hosted - version: "0.2.1+3" + version: "0.2.1+5" characters: dependency: transitive description: @@ -325,7 +325,7 @@ packages: name: flutter_plugin_android_lifecycle url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.6" flutter_test: dependency: "direct dev" description: flutter @@ -433,28 +433,28 @@ packages: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.8.5" + version: "0.8.5+1" image_picker_android: dependency: transitive description: name: image_picker_android url: "https://pub.dartlang.org" source: hosted - version: "0.8.4+11" + version: "0.8.4+12" image_picker_for_web: dependency: transitive description: name: image_picker_for_web url: "https://pub.dartlang.org" source: hosted - version: "2.1.6" + version: "2.1.7" image_picker_ios: dependency: transitive description: name: image_picker_ios url: "https://pub.dartlang.org" source: hosted - version: "0.8.5" + version: "0.8.5+1" image_picker_platform_interface: dependency: transitive description: @@ -580,35 +580,35 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "2.0.9" + version: "2.0.10" path_provider_android: dependency: transitive description: name: path_provider_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.13" + version: "2.0.14" path_provider_ios: dependency: transitive description: name: path_provider_ios url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.0.9" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "2.1.6" path_provider_macos: dependency: transitive description: name: path_provider_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.6" path_provider_platform_interface: dependency: transitive description: @@ -622,7 +622,7 @@ packages: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.6" petitparser: dependency: transitive description: @@ -727,35 +727,35 @@ packages: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "2.0.13" + version: "2.0.14" shared_preferences_android: dependency: transitive description: name: shared_preferences_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.12" shared_preferences_ios: dependency: transitive description: name: shared_preferences_ios url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.4" shared_preferences_platform_interface: dependency: transitive description: @@ -769,14 +769,14 @@ packages: name: shared_preferences_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.4" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" shelf: dependency: transitive description: @@ -879,35 +879,35 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "6.1.0" + version: "6.1.1" url_launcher_android: dependency: transitive description: name: url_launcher_android url: "https://pub.dartlang.org" source: hosted - version: "6.0.16" + version: "6.0.17" url_launcher_ios: dependency: transitive description: name: url_launcher_ios url: "https://pub.dartlang.org" source: hosted - version: "6.0.15" + version: "6.0.16" url_launcher_linux: dependency: transitive description: name: url_launcher_linux url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" url_launcher_platform_interface: dependency: transitive description: @@ -921,14 +921,14 @@ packages: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.9" + version: "2.0.10" url_launcher_windows: dependency: transitive description: name: url_launcher_windows url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" vector_math: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 35e0057..130d018 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: hive_flutter: ^1.1.0 image_picker: ^0.8.5 nb_utils: ^4.5.0 - path_provider: ^2.0.9 + path_provider: ^2.0.10 share_plus: ^4.0.4 flutter_intl: diff --git a/ios/Classes/src/native_zxing.cpp b/ios/Classes/src/native_zxing.cpp index 5002977..fca7183 100644 --- a/ios/Classes/src/native_zxing.cpp +++ b/ios/Classes/src/native_zxing.cpp @@ -10,7 +10,7 @@ using namespace ZXing; extern "C" { FUNCTION_ATTRIBUTE - char *version() + char const *version() { return "1.3.0"; } @@ -21,7 +21,7 @@ extern "C" long long start = get_now(); long length = width * height; - uint8_t *data = new uint8_t[length]; + auto *data = new uint8_t[length]; memcpy(data, bytes, length); BarcodeFormats formats = BarcodeFormat(format); // BarcodeFormat::Any; @@ -57,7 +57,7 @@ extern "C" long long start = get_now(); long length = width * height; - uint8_t *data = new uint8_t[length]; + auto *data = new uint8_t[length]; memcpy(data, bytes, length); BarcodeFormats formats = BarcodeFormat(format); // BarcodeFormat::Any; @@ -69,7 +69,7 @@ extern "C" } Results results = ReadBarcodes(image, hints); - struct CodeResult *codes = new struct CodeResult [results.size()]; + auto *codes = new struct CodeResult [results.size()]; int i = 0; for (auto &result : results) { diff --git a/ios/Classes/src/native_zxing.h b/ios/Classes/src/native_zxing.h index ff40b6a..000b67a 100644 --- a/ios/Classes/src/native_zxing.h +++ b/ios/Classes/src/native_zxing.h @@ -46,11 +46,11 @@ extern "C" }; /** - * Returns the version of the zxing library. + * Returns the version of the zxing-cpp library. * - * @return The version of the zxing library. + * @return The version of the zxing-cpp library. */ - char *version(); + char const *version(); /** * @brief Reads barcode from image. diff --git a/lib/flutter_zxing.dart b/lib/flutter_zxing.dart index d488883..de2c80c 100644 --- a/lib/flutter_zxing.dart +++ b/lib/flutter_zxing.dart @@ -23,7 +23,7 @@ class FlutterZxing { static final bindings = GeneratedBindings(dylib); - static bool logEnabled = true; + static bool logEnabled = false; static String version() { return bindings.version().cast().toDartString(); diff --git a/lib/generated_bindings.dart b/lib/generated_bindings.dart index 1a67a93..d5778ab 100644 --- a/lib/generated_bindings.dart +++ b/lib/generated_bindings.dart @@ -19,9 +19,9 @@ class GeneratedBindings { lookup) : _lookup = lookup; - /// Returns the version of the zxing library. + /// Returns the version of the zxing-cpp library. /// - /// @return The version of the zxing library. + /// @return The version of the zxing-cpp library. ffi.Pointer version() { return _version(); } diff --git a/lib/zxing_writer_widget.dart b/lib/zxing_writer_widget.dart index 1c2ac09..aa8d029 100644 --- a/lib/zxing_writer_widget.dart +++ b/lib/zxing_writer_widget.dart @@ -23,6 +23,13 @@ class _ZxingWriterWidgetState extends State with TickerProviderStateMixin { final GlobalKey _formKey = GlobalKey(); final TextEditingController _textController = TextEditingController(); + final TextEditingController _widthController = + TextEditingController(text: "300"); + final TextEditingController _heightController = + TextEditingController(text: "300"); + final TextEditingController _marginController = + TextEditingController(text: "10"); + final TextEditingController _eccController = TextEditingController(text: "0"); bool isAndroid() => Theme.of(context).platform == TargetPlatform.android; @@ -41,6 +48,30 @@ class _ZxingWriterWidgetState extends State mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ + const SizedBox(height: 20), + // Input multiline text + TextFormField( + controller: _textController, + keyboardType: TextInputType.multiline, + maxLines: null, + maxLength: _maxTextLength, + onChanged: (value) { + setState(() {}); + }, + decoration: InputDecoration( + border: const OutlineInputBorder(), + filled: true, + labelText: 'Enter barcode text here', + counterText: + '${_textController.value.text.length} / $_maxTextLength', + ), + validator: (value) { + if (value?.isEmpty == true) { + return 'Please enter some text'; + } + return null; + }, + ), const SizedBox(height: 20), // Format DropDown button DropdownButtonFormField( @@ -58,54 +89,85 @@ class _ZxingWriterWidgetState extends State }, ), const SizedBox(height: 20), - // Input multiline text - TextFormField( - controller: _textController, - keyboardType: TextInputType.multiline, - maxLines: null, - maxLength: _maxTextLength, - onChanged: (value) { - setState(() {}); - }, - decoration: InputDecoration( - border: const OutlineInputBorder(), - filled: true, - hintText: 'Enter text to create a barcode', - counterText: - '${_textController.value.text.length} / $_maxTextLength', - ), + Row( + children: [ + Flexible( + child: TextFormField( + controller: _widthController, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + labelText: 'Width', + ), + validator: (value) { + final width = int.tryParse(value ?? ''); + if (width == null) { + return 'Invalid number'; + } + return null; + }, + ), + ), + const SizedBox(width: 8), + Flexible( + child: TextFormField( + controller: _heightController, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + labelText: 'Height', + ), + validator: (value) { + final width = int.tryParse(value ?? ''); + if (width == null) { + return 'Invalid number'; + } + return null; + }, + ), + ), + ], + ), + const SizedBox(height: 20), + Row( + children: [ + Flexible( + child: TextFormField( + controller: _marginController, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + labelText: 'Margin', + ), + validator: (value) { + final width = int.tryParse(value ?? ''); + if (width == null) { + return 'Invalid number'; + } + return null; + }, + ), + ), + const SizedBox(width: 8), + Flexible( + child: TextFormField( + controller: _eccController, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + labelText: 'ECC Level', + ), + validator: (value) { + final width = int.tryParse(value ?? ''); + if (width == null) { + return 'Invalid number'; + } + return null; + }, + ), + ), + ], ), + const SizedBox(height: 20), // Write button ElevatedButton( - onPressed: () { - if (_formKey.currentState?.validate() ?? false) { - _formKey.currentState?.save(); - FocusScope.of(context).unfocus(); - final text = _textController.value.text; - const width = 300; - const height = 300; - var result = FlutterZxing.encodeBarcode( - text, width, height, _codeFormat, 5, 0); - String? error; - if (result.isValidBool) { - try { - final img = - imglib.Image.fromBytes(width, height, result.bytes); - final encodedBytes = - Uint8List.fromList(imglib.encodeJpg(img)); - widget.onSuccess?.call(result, encodedBytes); - } on Exception catch (e) { - error = e.toString(); - } - } else { - error = result.errorMessage; - } - if (error != null) { - debugPrint(error); - widget.onError?.call(error); - } - } - }, + onPressed: createBarcode, child: const Text('Create'), ), const SizedBox(height: 20), @@ -115,4 +177,34 @@ class _ZxingWriterWidgetState extends State ), ); } + + void createBarcode() { + if (_formKey.currentState?.validate() ?? false) { + _formKey.currentState?.save(); + FocusScope.of(context).unfocus(); + final text = _textController.value.text; + final width = int.parse(_widthController.value.text); + final height = int.parse(_heightController.value.text); + final margin = int.parse(_marginController.value.text); + final ecc = int.parse(_eccController.value.text); + var result = FlutterZxing.encodeBarcode( + text, width, height, _codeFormat, margin, ecc); + String? error; + if (result.isValidBool) { + try { + final img = imglib.Image.fromBytes(width, height, result.bytes); + final encodedBytes = Uint8List.fromList(imglib.encodeJpg(img)); + widget.onSuccess?.call(result, encodedBytes); + } on Exception catch (e) { + error = e.toString(); + } + } else { + error = result.errorMessage; + } + if (error != null) { + debugPrint(error); + widget.onError?.call(error); + } + } + } }