Skip to content

Conversation

Vishveshwara
Copy link
Contributor

@Vishveshwara Vishveshwara commented Jul 17, 2025

Fixes #86

Changes

  • Created Employee Id form and also a preview using a card widget and listeners update it
  • Uses pro_image_editor for positioning the elements and creating the image of the ID

Screenshots / Recordings

Checklist:

  • No hard coding: I have used resources from constants.dart without hard coding any value.
  • No end of file edits: No modifications done at end of resource files.
  • Code reformatting: I have reformatted code and fixed indentation in every file included in this pull request.
  • Code analyzation: My code passes analyzations run in flutter analyze and tests run in flutter test.

Summary by Sourcery

Introduce customizable card templates by adding template selection, form screens for employee IDs and price tags, layer specification utilities, and integration with the pro_image_editor to generate template-based images

New Features:

  • Add CardTemplateSelectionView for choosing Employee ID and Shop Price Tag templates
  • Implement EmployeeIdForm and PriceTagForm for user input and live preview of card templates
  • Integrate barcode generation and image picker for dynamic content in card templates
  • Enable passing predefined layers to MovableBackgroundImageExample for template-based image creation

Enhancements:

  • Extend MovableBackgroundImageExample to accept and render initial layers
  • Introduce LayerSpec utility class for composing text and widget layers
  • Automatically set portrait orientation in the image editor on startup

Build:

  • Add barcode_widget dependency for barcode rendering

Copy link
Contributor

sourcery-ai bot commented Jul 17, 2025

Reviewer's Guide

This PR implements a customizable template workflow by letting users select from predefined card templates (employee ID and price tag), fill out form fields with live previews, and preload the resulting LayerSpec entries into the MovableBackgroundImage editor for further adjustment or export.

Sequence diagram for template selection and layer preloading

sequenceDiagram
    actor User
    participant ImageEditor as ImageEditorView
    participant TemplateView as CardTemplateSelectionView
    participant Form as TemplateForm (EmployeeIdForm/PriceTagForm)
    participant Editor as MovableBackgroundImageExample

    User->>ImageEditor: Tap 'Templates' action
    ImageEditor->>TemplateView: Open CardTemplateSelectionView
    User->>TemplateView: Selects a template
    TemplateView->>Form: Open corresponding form
    User->>Form: Fill out form fields, see live preview
    User->>Form: Submit form
    Form->>Editor: Open MovableBackgroundImageExample with initialLayers
    Editor->>User: Show editor with preloaded layers
    User->>Editor: Optionally edit layers
    User->>ImageEditor: Save/export final image
Loading

Class diagram for new and updated template-related models

classDiagram
    class LayerSpec {
      +Widget? widget
      +String? text
      +TextStyle? textStyle
      +Color? textColor
      +Color? backgroundColor
      +TextAlign? textAlign
      +Offset offset
      +double scale
      +double rotation
      +LayerSpec.text(...)
      +LayerSpec.widget(...)
    }
    class EmployeeIdModel {
      +String companyName
      +String name
      +String idNumber
      +String division
      +String position
      +String qrData
      +File? profileImage
    }
    class PriceTagModel {
      +String productName
      +String price
      +String currency
      +String quantity
      +String barcodeData
      +File? productImage
    }
Loading

Class diagram for new template form and widget classes

classDiagram
    class EmployeeIdForm {
      +int width
      +int height
      +EmployeeIdForm(...)
    }
    class EmployeeIdCardWidget {
      +EmployeeIdModel data
      +EmployeeIdCardWidget(...)
    }
    class PriceTagForm {
      +int width
      +int height
      +PriceTagForm(...)
    }
    class PriceTagCardWidget {
      +PriceTagModel data
      +PriceTagCardWidget(...)
    }
    class CardTemplateSelectionView {
      +int width
      +int height
      +CardTemplateSelectionView(...)
    }
    EmployeeIdForm --> EmployeeIdCardWidget : uses
    PriceTagForm --> PriceTagCardWidget : uses
    CardTemplateSelectionView --> EmployeeIdForm : opens
    CardTemplateSelectionView --> PriceTagForm : opens
Loading

File-Level Changes

Change Details Files
Integrated initialLayers support into the image editor
  • Added initialLayers parameter to the editor widget
  • Implemented addInitialLayers to map LayerSpec entries into TextLayer and WidgetLayer instances
  • Invoked addInitialLayers during build when initialLayers is provided
  • Enforced portrait orientation on editor init
lib/pro_image_editor/features/movable_background_image.dart
Added 'Templates' action in the bottom action menu
  • Inserted a Templates button that navigates to CardTemplateSelectionView
  • Awaited Uint8List result from the template flow and updated the image loader
  • Saved finalized image bytes and signaled source change on template import
lib/view/image_editor.dart
Introduced LayerSpec utility for defining editable layers
  • Created LayerSpec class with text and widget constructors
  • Supported offset, scale, rotation, and styling properties for layers
lib/util/template_util.dart
Implemented card template selection, forms, previews, and models
  • Built CardTemplateSelectionView to route to Employee ID and Price Tag forms
  • Created EmployeeIdForm and PriceTagForm with form fields, live preview widgets, and LayerSpec generation
  • Added EmployeeIdCardWidget and PriceTagCardWidget for preview layouts
  • Defined EmployeeIdModel and PriceTagModel to back form data
lib/card_templates/card_template_selection_view.dart
lib/card_templates/employee_id_form.dart
lib/card_templates/price_tag_form.dart
lib/card_templates/employee_id_card_widget.dart
lib/card_templates/price_tag_card_widget.dart
lib/card_templates/employee_id_model.dart
lib/card_templates/price_tag_model.dart
Updated dependencies to support barcode and QR code rendering
  • Added barcode_widget dependency in pubspec.yaml
pubspec.yaml

Assessment against linked issues

Issue Objective Addressed Explanation
#86 Implement customizable templates for three types of cards: Employee ID card, Shop price tag, and Entry pass tag. The PR implements customizable templates for Employee ID card and Shop price tag, but the Entry pass tag template is not implemented (it is only mentioned as a TODO in the code).
#86 Support barcode for shop price tag, and QR code as an option for Employee ID and Entry Pass cards.
#86 Provide a scalable, editable, and shareable template system with editing features: different font support, font size adjustment, draggable/movable elements, resizable/movable images, and movable QR/barcode elements.

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

@Vishveshwara Vishveshwara marked this pull request as draft July 17, 2025 10:26
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 and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `lib/card_templates/employee_id_card_widget.dart:61` </location>
<code_context>
+              ),
+            const SizedBox(height: 4),
+            // Name
+            if (data.name.isNotEmpty)
+              Text(
+                'Name: ${data.name}',
+                style:
</code_context>

<issue_to_address>
Name is displayed twice in the card widget.

Remove one of the duplicate name fields to prevent redundancy in the card display.
</issue_to_address>

### Comment 2
<location> `lib/card_templates/employee_id_form.dart:113` </location>
<code_context>
+        ));
+      }
+
+      // Profile Image Layer
+      if (_profileImage != null) {
+        layers.add(LayerSpec(
+          widget: ClipRRect(
+            borderRadius: BorderRadius.circular(8.0),
+            child: Image.file(_profileImage!,
+                width: 200, height: 200, fit: BoxFit.cover),
+          ),
+          offset: const Offset(0, -205),
+          scale: 10,
+        ));
+      }
+
</code_context>

<issue_to_address>
Profile image and company name layers have overlapping offsets.

Adjust the offsets to prevent visual overlap between the profile image and company name layers.

Suggested implementation:

```
          widget: Text(
            _employeeData.companyName,
            style: const TextStyle(
                fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black),
          ),
          offset: const Offset(0, -240), // Moved company name higher
          scale: 10,
        ));
      }

```

```
      // Profile Image Layer
      if (_profileImage != null) {
        layers.add(LayerSpec(
          widget: ClipRRect(
            borderRadius: BorderRadius.circular(8.0),
            child: Image.file(_profileImage!,
                width: 200, height: 200, fit: BoxFit.cover),
          ),
          offset: const Offset(0, -180), // Moved profile image lower
          scale: 10,
        ));
      }

```
</issue_to_address>

### Comment 3
<location> `lib/card_templates/employee_id_form.dart:180` </location>
<code_context>
+      ));
+
+      // QR Code Layer (bottom, only if qrData is not empty)
+      if (_employeeData.qrData.isNotEmpty) {
+        layers.add(LayerSpec(
+          widget: BarcodeWidget(
+            barcode: Barcode.qrCode(),
+            data: _employeeData.qrData,
+            width: 60,
+            height: 60,
+          ),
+          offset: const Offset(0, 170),
+          scale: 8,
+        ));
+      }
+
</code_context>

<issue_to_address>
No error handling for invalid QR data.

Validate the QR data or add exception handling to avoid runtime errors if the data is invalid.
</issue_to_address>

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.

const SizedBox(height: 8),
// Company Name
if (data.companyName.isNotEmpty)
Text(
Copy link
Contributor

Choose a reason for hiding this comment

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

issue: Name is displayed twice in the card widget.

Remove one of the duplicate name fields to prevent redundancy in the card display.

),
offset: const Offset(0, -210),
scale: 10,
));
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Profile image and company name layers have overlapping offsets.

Adjust the offsets to prevent visual overlap between the profile image and company name layers.

Suggested implementation:

          widget: Text(
            _employeeData.companyName,
            style: const TextStyle(
                fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black),
          ),
          offset: const Offset(0, -240), // Moved company name higher
          scale: 10,
        ));
      }

      // Profile Image Layer
      if (_profileImage != null) {
        layers.add(LayerSpec(
          widget: ClipRRect(
            borderRadius: BorderRadius.circular(8.0),
            child: Image.file(_profileImage!,
                width: 200, height: 200, fit: BoxFit.cover),
          ),
          offset: const Offset(0, -180), // Moved profile image lower
          scale: 10,
        ));
      }

),
offset: const Offset(0, -210),
scale: 10,
));
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): No error handling for invalid QR data.

Validate the QR data or add exception handling to avoid runtime errors if the data is invalid.

@Vishveshwara
Copy link
Contributor Author

emp.mp4

@hpdang
Copy link
Member

hpdang commented Jul 21, 2025

@Vishveshwara how far are you with this draft PR?

@Vishveshwara
Copy link
Contributor Author

@Vishveshwara how far are you with this draft PR?

@hpdang , actually I can finish implementing this in the same way i have done for the employee id , but there is a method to adjust the fonts in the editor , but i am getting an error when using the text layer in the pro_image_editor package , I am going to create a discussion in their github repository , so that we can change the fonts in the editor.

@Vishveshwara
Copy link
Contributor Author

@hpdang , Added shopping price tag and text layer to adjust fonts or modify the text in the editor itself.

price.tag.vid.mp4

@Vishveshwara Vishveshwara marked this pull request as ready for review July 23, 2025 06:54
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:

  • You’re adding initial layers inside the build callback, which risks duplication on rebuilds—consider moving that logic to initState (or a post‐frame callback) so layers are only applied once.
  • The two form widgets (EmployeeIdForm and PriceTagForm) share a lot of boilerplate for controller setup, preview updates and layer generation—consider extracting a common base or helper to reduce duplication.
  • Please remove the commented-out "code testing" snippets once you’ve verified functionality to keep the code clean and maintainable.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- You’re adding initial layers inside the build callback, which risks duplication on rebuilds—consider moving that logic to initState (or a post‐frame callback) so layers are only applied once.
- The two form widgets (EmployeeIdForm and PriceTagForm) share a lot of boilerplate for controller setup, preview updates and layer generation—consider extracting a common base or helper to reduce duplication.
- Please remove the commented-out "code testing" snippets once you’ve verified functionality to keep the code clean and maintainable.

## Individual Comments

### Comment 1
<location> `lib/pro_image_editor/features/movable_background_image.dart:456` </location>
<code_context>
                     );
+
+                    // Add initial layers from widget parameter
+                    if (widget.initialLayers != null) {
+                      addInitialLayers(widget.initialLayers!);
+                    }
+                    //code testing
+                    //editorKey.currentState!.openTextEditor(initialText: "Hello World");
</code_context>

<issue_to_address>
Adding initial layers inside the build method can lead to unexpected behavior.

The build method may be called multiple times, causing duplicate layers. Move this logic to an initialization phase to prevent repeated additions.
</issue_to_address>

### Comment 2
<location> `lib/util/template_util.dart:4` </location>
<code_context>
+class LayerSpec {
</code_context>

<issue_to_address>
LayerSpec allows both widget and text to be set, which could lead to ambiguous layer definitions.

The main constructor currently permits both fields to be set, which may introduce ambiguity. Making it private and using only named constructors would enforce clearer usage.
</issue_to_address>

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 +4 to +13
class LayerSpec {
final Widget? widget;
final String? text;
final TextStyle? textStyle;
final Color? textColor;
final Color? backgroundColor;
final TextAlign? textAlign;
final Offset offset;
final double scale;
final double rotation;
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (bug_risk): LayerSpec allows both widget and text to be set, which could lead to ambiguous layer definitions.

The main constructor currently permits both fields to be set, which may introduce ambiguity. Making it private and using only named constructors would enforce clearer usage.

@hpdang hpdang requested a review from Dhruv1797 July 23, 2025 10:15
@Vishveshwara Vishveshwara requested a review from AsCress July 23, 2025 14:21
Copy link
Contributor

github-actions bot commented Jul 25, 2025

Build Status

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

@hpdang
Copy link
Member

hpdang commented Jul 30, 2025

@Vishveshwara please see screenshot below, why there is a line of text covering the bottom menu?

9b789db4-3710-4d42-a0cb-dd75e3463254

@hpdang hpdang self-requested a review July 30, 2025 13:31
@hpdang
Copy link
Member

hpdang commented Aug 1, 2025

@Vishveshwara please fix error and resolve conflicts

@Vishveshwara
Copy link
Contributor Author

Vishveshwara commented Aug 1, 2025

@hpdang
Copy link
Member

hpdang commented Aug 2, 2025

Tested. The bottom text is not there anymore. It showed debug label on the top though, is it intended? @Vishveshwara

@Vishveshwara
Copy link
Contributor Author

Tested. The bottom text is not there anymore. It showed debug label on the top though, is it intended? @Vishveshwara

@hpdang
Can you please share the screenshot , I am unable to replicate the error you are facing.

@hpdang
Copy link
Member

hpdang commented Aug 3, 2025

Tested. The bottom text is not there anymore. It showed debug label on the top though, is it intended? @Vishveshwara

@hpdang Can you please share the screenshot , I am unable to replicate the error you are facing.

2025-08-03 at 11 00 54 PM
2025-08-03 at 11 00 53 PM

@Vishveshwara
Copy link
Contributor Author

Tested. The bottom text is not there anymore. It showed debug label on the top though, is it intended? @Vishveshwara

@hpdang Can you please share the screenshot , I am unable to replicate the error you are facing.

2025-08-03 at 11 00 54 PM 2025-08-03 at 11 00 53 PM

@hpdang this is not an issue, this is just a debug build version of the app which is used for testing and quick debugging, the release version of the app will remove the debug label.

@hpdang hpdang merged commit 66bd8a7 into fossasia:main Aug 6, 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.

Customizable Templates for the Employee ID/Tags
3 participants