Skip to content

Conversation

Vishveshwara
Copy link
Contributor

@Vishveshwara Vishveshwara commented Jul 30, 2025

Fixes #98

Utilizes mobile_scanner package for scanning the barcodes in real time and uses the barcode_widget for generating an image.

Summary by Sourcery

Add a new Barcode Scanner and Generator screen to enable real-time scanning and image generation of various barcode formats, integrate it into the image editor menu, and configure required permissions and dependencies.

New Features:

  • Introduce BarcodeScannerScreen for scanning barcodes using the camera and generating barcode images for use in the editor
  • Add a ‘Barcode’ action button in the image editor bottom menu to navigate to the new scanner screen

Enhancements:

  • Add camera and photo library usage descriptions to iOS Info.plist
  • Enable unbundled mobile_scanner usage in Android via gradle.properties

Build:

  • Include mobile_scanner and barcode_widget packages in pubspec.yaml

@Vishveshwara Vishveshwara requested a review from Dhruv1797 July 30, 2025 13:24
Copy link
Contributor

sourcery-ai bot commented Jul 30, 2025

Reviewer's Guide

Introduces a dedicated barcode generator screen integrated into the image editor, leveraging mobile_scanner for live scanning, barcode_widget for preview and generation logic, and updates navigation and platform permissions accordingly.

Sequence diagram for barcode scanning and image generation

sequenceDiagram
    actor User
    participant ImageEditor as Image Editor
    participant BarcodeScreen as BarcodeScannerScreen
    participant Scanner as mobile_scanner
    participant BarcodeWidget
    participant Navigator

    User->ImageEditor: Tap 'Barcode' button
    ImageEditor->Navigator: Push BarcodeScannerScreen
    Navigator->BarcodeScreen: Show BarcodeScannerScreen
    User->BarcodeScreen: Tap 'Scan Barcode'
    BarcodeScreen->Scanner: Start scanning
    Scanner->BarcodeScreen: Return scanned barcode data
    BarcodeScreen->BarcodeWidget: Update preview
    User->BarcodeScreen: Tap 'Generate Image'
    BarcodeScreen->BarcodeWidget: Render barcode
    BarcodeScreen->ImageEditor: Return generated image
Loading

Class diagram for BarcodeScannerScreen and related logic

classDiagram
    class BarcodeScannerScreen {
      +int width
      +int height
    }
    BarcodeScannerScreen <|-- _BarcodeScannerScreenState
    class _BarcodeScannerScreenState {
      -GlobalKey _barcodeKey
      -TextEditingController _textController
      -String _barcodeData
      -bool _hasError
      -Barcode _selectedBarcode
      -bool _showScanner
      -MobileScannerController? _scannerController
      +void _handleBarcode(BarcodeCapture)
      +void _startScanning()
      +void _stopScanning()
      +Barcode _getBarcodeType(BarcodeFormat?)
      +Future<void> _generateBarcodeImage()
      +Widget _buildFormatSelector()
      +Widget _buildBarcodePreview()
      +Widget _buildScannerView()
      +Widget build(BuildContext)
    }
    class MobileScannerController
    class Barcode
    class BarcodeCapture
    class BarcodeWidget
    class TextEditingController
    class GlobalKey
    BarcodeScannerScreen o-- _BarcodeScannerScreenState
    _BarcodeScannerScreenState o-- MobileScannerController
    _BarcodeScannerScreenState o-- Barcode
    _BarcodeScannerScreenState o-- BarcodeWidget
    _BarcodeScannerScreenState o-- TextEditingController
    _BarcodeScannerScreenState o-- GlobalKey
Loading

File-Level Changes

Change Details Files
Added a new BarcodeScannerScreen for generating and scanning barcodes
  • Created stateful widget with text input, format dropdown, preview, and generate button
  • Implemented live camera scanning mode with mobile_scanner and format detection
  • Captured RepaintBoundary to render barcode widget to image bytes and resized/rotated output
lib/view/barcode_scanner_screen.dart
Integrated barcode option into the BottomActionMenu
  • Imported BarcodeScannerScreen and added 'Barcode' action button
  • Launched scanner screen via Navigator and handled returned image bytes
  • Updated imgLoader to display and save generated barcode image
lib/view/image_editor.dart
Updated dependencies and platform permissions for camera and barcode packages
  • Added mobile_scanner and barcode_widget to pubspec.yaml
  • Declared NSCameraUsageDescription and NSPhotoLibraryUsageDescription in Info.plist
  • Enabled unbundled scanning flag in android/gradle.properties
pubspec.yaml
ios/Runner/Info.plist
android/gradle.properties

Assessment against linked issues

Issue Objective Addressed Explanation
#98 Add a text input field to allow users to enter a string and automatically generate a barcode or QR code based on the input, with the ability to edit the object after insertion.
#98 Add functionality to scan an external barcode or QR code using the device camera and auto-fill the text field with the scanned content.
#98 Ensure the design and interactions for barcode and QR code features are consistent with existing image/text/object elements in the app.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Vishveshwara - I've reviewed your changes - here's some feedback:

  • Refactor the large BarcodeScannerScreen into smaller widgets or components (e.g. separate scanner view, format selector, and preview) to improve readability and maintainability.
  • Extract the barcode format mapping into a single shared map or helper to avoid duplicating logic in both _getBarcodeType and _buildFormatSelector.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Refactor the large BarcodeScannerScreen into smaller widgets or components (e.g. separate scanner view, format selector, and preview) to improve readability and maintainability.
- Extract the barcode format mapping into a single shared map or helper to avoid duplicating logic in both _getBarcodeType and _buildFormatSelector.

## Individual Comments

### Comment 1
<location> `lib/view/barcode_scanner_screen.dart:201` </location>
<code_context>
+  }
+
+  Widget _buildBarcodePreview() {
+    if (_barcodeData.isEmpty) {
+      return Container(
+        width: 240,
+        height: 120,
</code_context>

<issue_to_address>
Empty barcode data disables format selection and image generation.

Consider enabling format selection even when no barcode data is entered, so users can choose a format before providing data.

Suggested implementation:

```
  Widget _buildBarcodePreview() {
    if (_barcodeData.isEmpty) {
      return Column(
        children: [
          _buildFormatSelector(), // Always show format selector
          const SizedBox(height: 12),
          Container(
            width: 240,
            height: 120,
            decoration: BoxDecoration(
              color: Colors.grey[200],
              border: Border.all(color: Colors.grey),
              borderRadius: BorderRadius.circular(8),
            ),
            child: const Center(
              child: Text(
                'Enter or scan barcode data',
                style: TextStyle(color: Colors.grey),
              ),
            ),
          ),
        ],
      );

```

If `_buildFormatSelector()` was previously only shown when barcode data was present, you should also ensure that in the "else" branch of `_buildBarcodePreview` (when `_barcodeData` is not empty), the format selector is still shown above the preview. If `_buildFormatSelector()` is not already implemented, you will need to implement it to provide the format selection UI.
</issue_to_address>

### Comment 2
<location> `lib/view/barcode_scanner_screen.dart:221` </location>
<code_context>
+
+    return BarcodeWidget(
+      errorBuilder: (context, error) {
+        WidgetsBinding.instance.addPostFrameCallback((_) {
+          setState(() {
+            _hasError = true;
+          });
</code_context>

<issue_to_address>
Calling setState in errorBuilder may cause unnecessary rebuilds.

Consider handling error state outside the errorBuilder to prevent repeated setState calls and potential performance issues.
</issue_to_address>

### Comment 3
<location> `lib/view/barcode_scanner_screen.dart:138` </location>
<code_context>
+  }
+
+  Widget _buildFormatSelector() {
+    final Map<String, Barcode> availableFormats = {
+      'QR Code': Barcode.qrCode(),
+      'Data Matrix': Barcode.dataMatrix(),
+      'Aztec': Barcode.aztec(),
+      'PDF417': Barcode.pdf417(),
+      'Code 128': Barcode.code128(),
+      'Code 93': Barcode.code93(),
+      'Code 39': Barcode.code39(),
+      'Codabar': Barcode.codabar(),
+      'EAN-13': Barcode.ean13(),
+      'EAN-8': Barcode.ean8(),
+      'EAN-5': Barcode.ean5(),
+      'EAN-2': Barcode.ean2(),
+      'GS1 128': Barcode.gs128(),
+      'ISBN': Barcode.isbn(),
+      'ITF': Barcode.itf(),
+      'ITF-16': Barcode.itf16(),
+      'ITF-14': Barcode.itf14(),
+      'RM4SCC': Barcode.rm4scc(),
+      'Telepen': Barcode.telepen(),
+      'UPC-A': Barcode.upcA(),
+      'UPC-E': Barcode.upcE(),
+    };
+
</code_context>

<issue_to_address>
Some barcode formats in the selector may not be supported by the scanner.

Some formats in availableFormats, such as ISBN, GS1 128, and Telepen, may not be supported by mobile_scanner or device hardware. Please filter out unsupported formats or clearly indicate which ones are unavailable.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
  Widget _buildFormatSelector() {
+    final Map<String, Barcode> availableFormats = {
+      'QR Code': Barcode.qrCode(),
+      'Data Matrix': Barcode.dataMatrix(),
+      'Aztec': Barcode.aztec(),
+      'PDF417': Barcode.pdf417(),
+      'Code 128': Barcode.code128(),
+      'Code 93': Barcode.code93(),
+      'Code 39': Barcode.code39(),
+      'Codabar': Barcode.codabar(),
+      'EAN-13': Barcode.ean13(),
+      'EAN-8': Barcode.ean8(),
+      'EAN-5': Barcode.ean5(),
+      'EAN-2': Barcode.ean2(),
+      'GS1 128': Barcode.gs128(),
+      'ISBN': Barcode.isbn(),
+      'ITF': Barcode.itf(),
+      'ITF-16': Barcode.itf16(),
+      'ITF-14': Barcode.itf14(),
+      'RM4SCC': Barcode.rm4scc(),
+      'Telepen': Barcode.telepen(),
+      'UPC-A': Barcode.upcA(),
+      'UPC-E': Barcode.upcE(),
+    };
=======
  Widget _buildFormatSelector() {
+    // Only include formats supported by mobile_scanner and most device hardware.
+    final Map<String, Barcode> availableFormats = {
+      'QR Code': Barcode.qrCode(),
+      'Data Matrix': Barcode.dataMatrix(),
+      'Aztec': Barcode.aztec(),
+      'PDF417': Barcode.pdf417(),
+      'Code 128': Barcode.code128(),
+      'Code 93': Barcode.code93(),
+      'Code 39': Barcode.code39(),
+      'Codabar': Barcode.codabar(),
+      'EAN-13': Barcode.ean13(),
+      'EAN-8': Barcode.ean8(),
+      'ITF': Barcode.itf(),
+      'UPC-A': Barcode.upcA(),
+      'UPC-E': Barcode.upcE(),
+      // Add more formats here if confirmed supported by mobile_scanner and device hardware.
+    };
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +201 to +202
if (_barcodeData.isEmpty) {
return Container(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Empty barcode data disables format selection and image generation.

Consider enabling format selection even when no barcode data is entered, so users can choose a format before providing data.

Suggested implementation:

  Widget _buildBarcodePreview() {
    if (_barcodeData.isEmpty) {
      return Column(
        children: [
          _buildFormatSelector(), // Always show format selector
          const SizedBox(height: 12),
          Container(
            width: 240,
            height: 120,
            decoration: BoxDecoration(
              color: Colors.grey[200],
              border: Border.all(color: Colors.grey),
              borderRadius: BorderRadius.circular(8),
            ),
            child: const Center(
              child: Text(
                'Enter or scan barcode data',
                style: TextStyle(color: Colors.grey),
              ),
            ),
          ),
        ],
      );

If _buildFormatSelector() was previously only shown when barcode data was present, you should also ensure that in the "else" branch of _buildBarcodePreview (when _barcodeData is not empty), the format selector is still shown above the preview. If _buildFormatSelector() is not already implemented, you will need to implement it to provide the format selection UI.

void initState() {
super.initState();
_textController.addListener(() {
setState(() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (performance): Calling setState in errorBuilder may cause unnecessary rebuilds.

Consider handling error state outside the errorBuilder to prevent repeated setState calls and potential performance issues.

Comment on lines +137 to +160
Widget _buildFormatSelector() {
final Map<String, Barcode> availableFormats = {
'QR Code': Barcode.qrCode(),
'Data Matrix': Barcode.dataMatrix(),
'Aztec': Barcode.aztec(),
'PDF417': Barcode.pdf417(),
'Code 128': Barcode.code128(),
'Code 93': Barcode.code93(),
'Code 39': Barcode.code39(),
'Codabar': Barcode.codabar(),
'EAN-13': Barcode.ean13(),
'EAN-8': Barcode.ean8(),
'EAN-5': Barcode.ean5(),
'EAN-2': Barcode.ean2(),
'GS1 128': Barcode.gs128(),
'ISBN': Barcode.isbn(),
'ITF': Barcode.itf(),
'ITF-16': Barcode.itf16(),
'ITF-14': Barcode.itf14(),
'RM4SCC': Barcode.rm4scc(),
'Telepen': Barcode.telepen(),
'UPC-A': Barcode.upcA(),
'UPC-E': Barcode.upcE(),
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Some barcode formats in the selector may not be supported by the scanner.

Some formats in availableFormats, such as ISBN, GS1 128, and Telepen, may not be supported by mobile_scanner or device hardware. Please filter out unsupported formats or clearly indicate which ones are unavailable.

Suggested change
Widget _buildFormatSelector() {
final Map<String, Barcode> availableFormats = {
'QR Code': Barcode.qrCode(),
'Data Matrix': Barcode.dataMatrix(),
'Aztec': Barcode.aztec(),
'PDF417': Barcode.pdf417(),
'Code 128': Barcode.code128(),
'Code 93': Barcode.code93(),
'Code 39': Barcode.code39(),
'Codabar': Barcode.codabar(),
'EAN-13': Barcode.ean13(),
'EAN-8': Barcode.ean8(),
'EAN-5': Barcode.ean5(),
'EAN-2': Barcode.ean2(),
'GS1 128': Barcode.gs128(),
'ISBN': Barcode.isbn(),
'ITF': Barcode.itf(),
'ITF-16': Barcode.itf16(),
'ITF-14': Barcode.itf14(),
'RM4SCC': Barcode.rm4scc(),
'Telepen': Barcode.telepen(),
'UPC-A': Barcode.upcA(),
'UPC-E': Barcode.upcE(),
};
Widget _buildFormatSelector() {
+ // Only include formats supported by mobile_scanner and most device hardware.
+ final Map<String, Barcode> availableFormats = {
+ 'QR Code': Barcode.qrCode(),
+ 'Data Matrix': Barcode.dataMatrix(),
+ 'Aztec': Barcode.aztec(),
+ 'PDF417': Barcode.pdf417(),
+ 'Code 128': Barcode.code128(),
+ 'Code 93': Barcode.code93(),
+ 'Code 39': Barcode.code39(),
+ 'Codabar': Barcode.codabar(),
+ 'EAN-13': Barcode.ean13(),
+ 'EAN-8': Barcode.ean8(),
+ 'ITF': Barcode.itf(),
+ 'UPC-A': Barcode.upcA(),
+ 'UPC-E': Barcode.upcE(),
+ // Add more formats here if confirmed supported by mobile_scanner and device hardware.
+ };

@Vishveshwara
Copy link
Contributor Author

WhatsApp.Video.2025-07-30.at.7.04.22.PM.mp4

Copy link
Contributor

github-actions bot commented Jul 30, 2025

Build Status

Build successful. APKs to test: https://github.com/fossasia/magic-epaper-app/actions/runs/16872887988/artifacts/3731890247.

@hpdang hpdang requested a review from marcnause July 30, 2025 13:52
@hpdang
Copy link
Member

hpdang commented Aug 6, 2025

@Dhruv1797 did you review this?

@Vishveshwara
Copy link
Contributor Author

screen-20250807-191249.mp4

@hpdang hpdang merged commit 45200ff into fossasia:main Aug 13, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Barcode and QR Code Support to App
4 participants