Skip to content

feat: Support for Multiple LED Badge sizes#1347

Closed
samruddhi-Rahegaonkar wants to merge 40 commits intofossasia:developmentfrom
samruddhi-Rahegaonkar:issue1344
Closed

feat: Support for Multiple LED Badge sizes#1347
samruddhi-Rahegaonkar wants to merge 40 commits intofossasia:developmentfrom
samruddhi-Rahegaonkar:issue1344

Conversation

@samruddhi-Rahegaonkar
Copy link
Copy Markdown
Member

@samruddhi-Rahegaonkar samruddhi-Rahegaonkar commented Jun 23, 2025

Fixes #1314

Changes

  • Introduced dynamic support for multiple badge screen sizes across the app.
  • Added new model: ScreenSize to support scalable layouts.
  • Refactored key components including:
  • draw_badge_screen.dart
  • badge_paint.dart
  • animated_badge.dart
  • Various providers: draw_badge_provider, saved_badge_provider, etc.
  • Updated converters and byte array utilities to respect dynamic screen dimensions.
  • Added/updated unit tests for converters and matrix logic.

Screenshots / Recordings

Screenshot 2025-06-26 at 1 06 07 PM Screenshot 2025-06-26 at 1 07 00 PM Screenshot 2025-06-26 at 1 07 30 PM Screenshot 2025-06-26 at 1 04 52 PM Screenshot 2025-06-26 at 1 05 13 PM Screenshot 2025-06-26 at 1 07 50 PM
Screen.Recording.2025-06-26.at.6.49.21.PM.mov

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 dynamic support for multiple LED badge sizes by adding a ScreenSize model and propagating variable dimensions throughout the UI, providers, converters, painting logic, and tests, while enabling users to select their badge size at runtime.

New Features:

  • Add support for multiple badge screen sizes via a new ScreenSize model and a size selector dropdown in the home and save badge UIs
  • Enable dynamic initialization and resizing of badge grids at runtime across drawing, animation, effects, and transfer workflows based on the selected ScreenSize

Enhancements:

  • Refactor core providers and utilities (AnimationBadgeProvider, DrawBadgeProvider, SavedBadgeProvider, BadgeMessageProvider) to accept badge height/width parameters and initialize grids dynamically
  • Update converters, byte‐array utilities, and custom painters to handle arbitrary badge dimensions
  • Clean up lifecycle handling and listener management in HomeScreen for consistent pause/resume behavior

CI:

  • Update GitHub Actions workflows to trigger on the development branch

Tests:

  • Revise converter and data‐to‐bytearray unit tests to include the badgeHeight parameter

Summary by Sourcery

Support multiple LED badge sizes by introducing a ScreenSize model and wiring dynamic width/height parameters throughout the app to enable scalable layouts in all drawing, animation, effect, saving, and transfer features.

New Features:

  • Introduce ScreenSize model with UI dropdown to select badge dimensions at runtime
  • Enable dynamic initialization and resizing of badge grids based on selected ScreenSize across drawing, animation, effects, and transfer workflows

Enhancements:

  • Refactor core providers and utilities to accept variable badge width/height parameters
  • Update converters, byte array utilities, and custom painters to support arbitrary badge dimensions
  • Enhance image utilities to scale and trim SVG/bitmap assets to match selected badge size
  • Propagate ScreenSize selection through UI components including AnimationBadge, EffectTab, SaveBadgeCard, and DrawBadge

CI:

  • Modify GitHub Actions workflows to trigger on development and flutter_app branches

Tests:

  • Update unit tests for converters and byte array utilities to include dynamic badge dimensions

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Jun 23, 2025

Reviewer's Guide

This PR adds dynamic support for multiple LED badge sizes by introducing a ScreenSize model and replacing all hard-coded grid dimensions with runtime-configurable values, propagating the selected size through UI widgets, providers, converters, custom painters, utilities, and tests.

Sequence diagram for badge size selection and propagation

sequenceDiagram
    actor User
    participant HomeScreen
    participant AnimationBadge
    participant DrawBadge
    participant SaveBadgeDialog
    participant SaveBadgeProvider
    User->>HomeScreen: Selects badge size from dropdown
    HomeScreen->>AnimationBadge: Passes selected ScreenSize
    User->>DrawBadge: Navigates to draw badge
    DrawBadge->>DrawBadge: Initializes grid with selected ScreenSize
    User->>SaveBadgeDialog: Opens save dialog
    SaveBadgeDialog->>SaveBadgeProvider: Saves badge with selected ScreenSize
    SaveBadgeProvider->>SaveBadgeProvider: Stores badge data with size info
Loading

Class diagram for ScreenSize and supportedScreenSizes

classDiagram
    class ScreenSize {
        +int width
        +int height
        +String name
        +operator ==(Object other)
        +int hashCode
    }
    class supportedScreenSizes {
        <<constant>>
        +List<ScreenSize>
    }
Loading

Class diagram for updated AnimationBadgeProvider and DrawBadgeProvider

classDiagram
    class AnimationBadgeProvider {
        -List<List<bool>> _paintGrid
        -List<List<bool>> _newGrid
        -List<List<List<bool>>> _frames
        -int _currentFrame
        +void initGrids(ScreenSize size)
        +void badgeAnimation(String, Converters, bool, ScreenSize)
        +List<List<bool>> getPaintGrid()
        +List<List<bool>> getNewGrid()
    }
    class DrawBadgeProvider {
        -List<List<bool>> _drawViewGrid
        -ScreenSize _currentSize
        +void initGridWithSize(ScreenSize size)
        +List<List<bool>> getDrawViewGrid()
        +ScreenSize getCurrentSize()
    }
Loading

Class diagram for updated UI widgets with ScreenSize support

classDiagram
    class AnimationBadge {
        +ScreenSize selectedSize
    }
    class BMBadge {
        +ScreenSize selectedSize
    }
    class EffectContainer {
        +ScreenSize selectedSize
    }
    class EffectTab {
        +ScreenSize selectedSize
    }
    class SaveBadgeCard {
        +ScreenSize selectedSize
    }
    class BadgeListView {
        +ScreenSize selectedSize
    }
    class SavedClipartListView {
        +ScreenSize selectedSize
    }
    class SaveBadgeDialog {
        +ScreenSize selectedSize
    }
Loading

File-Level Changes

Change Details Files
Add ScreenSize model and supported sizes
  • Define ScreenSize class with width, height, name
  • Initialize supportedScreenSizes list
  • Import and use ScreenSize where needed
lib/bademagic_module/models/screen_size.dart
UI updates to select and propagate badge size
  • Add dropdown and _selectedSize field in HomeScreen and SaveBadgeScreen
  • Pass selectedSize into AnimationBadge, BMBadge, EffectTab, SaveBadgeCard, SaveBadgeDialog, DrawBadgeScreen, ClipartListView
  • Update main.dart routes to include initial selectedSize
lib/view/homescreen.dart
lib/view/save_badge_screen.dart
lib/view/draw_badge_screen.dart
lib/view/saved_clipart.dart
lib/view/widgets/clipart_list_view.dart
lib/main.dart
lib/view/widgets/save_badge_card.dart
lib/view/widgets/save_badge_dialog.dart
lib/view/widgets/effects_container.dart
lib/view/widgets/homescreentabs.dart
lib/virtualbadge/view/animated_badge.dart
Refactor providers for dynamic dimensions
  • Replace hard-coded 44×11 grids with initGrids/initGridWithSize taking ScreenSize
  • Extend methods (badgeAnimation, saveBadgeData, getBadgeData) to accept badgeHeight/width
  • Update grid logic and notifyListeners accordingly
lib/providers/animation_badge_provider.dart
lib/providers/draw_badge_provider.dart
lib/providers/saved_badge_provider.dart
lib/providers/badge_message_provider.dart
Converters and utilities accept dynamic sizes
  • Change messageTohex signature to include badgeHeight and ScreenSize
  • Implement scaling/padding logic based on ScreenSize in converters
  • Update hexStringToBool, byteArrayToBinaryArray, binaryStringTo2DList to use rows parameter
  • Add generateLedHexWithSize in ImageUtils
lib/bademagic_module/utils/converters.dart
lib/bademagic_module/utils/byte_array_utils.dart
lib/bademagic_module/utils/image_utils.dart
Dynamic badge painting based on grid dimensions
  • Compute cellSize and aspectRatio from grid length and height
  • Guard against empty grids before painting
lib/virtualbadge/view/badge_paint.dart
Update tests for dynamic screen sizes
  • Pass badgeHeight and ScreenSize into messageTohex calls
  • Adjust expected hex outputs and utility calls
test/data_to_bytearray_converter_test.dart
test/converters_test.dart
Update CI workflows to include new branches
  • Add flutter_app branch trigger in pull_request_closed.yml
  • Ensure push.yml triggers remain correct
.github/workflows/pull_request_closed.yml
.github/workflows/push.yml

Assessment against linked issues

Issue Objective Addressed Explanation

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

@samruddhi-Rahegaonkar samruddhi-Rahegaonkar force-pushed the issue1344 branch 12 times, most recently from fc0ac96 to 74a1dda Compare June 28, 2025 04:34
@samruddhi-Rahegaonkar samruddhi-Rahegaonkar marked this pull request as ready for review June 28, 2025 04:55
Copy link
Copy Markdown
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 @samruddhi-Rahegaonkar - I've reviewed your changes - here's some feedback:

  • This change spreads the new ScreenSize parameters into almost every widget and provider method; consider using a single Provider or InheritedWidget to hold the selected badge size so you don’t have to modify every signature and widget.
  • The Converters.messageTohex method has become extremely large with mixed responsibilities (emoji tags, char scaling, bitmap scaling); refactor by extracting emoji, character, and bitmap conversion into separate helper classes or private services to improve readability and testability.
  • BadgePaint (and other rendering code) still uses magic scaling factors like 0.93 and 0.5—extract these into named constants or compute them dynamically from width/height ratios to avoid unexpected layout issues on non-standard sizes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- This change spreads the new ScreenSize parameters into almost every widget and provider method; consider using a single Provider or InheritedWidget to hold the selected badge size so you don’t have to modify every signature and widget.
- The Converters.messageTohex method has become extremely large with mixed responsibilities (emoji tags, char scaling, bitmap scaling); refactor by extracting emoji, character, and bitmap conversion into separate helper classes or private services to improve readability and testability.
- BadgePaint (and other rendering code) still uses magic scaling factors like 0.93 and 0.5—extract these into named constants or compute them dynamically from width/height ratios to avoid unexpected layout issues on non-standard sizes.

## Individual Comments

### Comment 1
<location> `lib/providers/animation_badge_provider.dart:110` </location>
<code_context>
   }

   void startTimer() {
+    if (_newGrid.isEmpty || _newGrid[0].isEmpty) {
+      logger.w("Cannot start animation timer: _newGrid is empty");
+      return;
</code_context>

<issue_to_address>
startTimer silently returns if _newGrid is empty, which may mask upstream issues.

Consider surfacing this condition as an error or notifying the caller, so they are aware the animation did not start.
</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 thread lib/providers/animation_badge_provider.dart
@samruddhi-Rahegaonkar
Copy link
Copy Markdown
Member Author

samruddhi-Rahegaonkar commented Jun 28, 2025

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

  • This change spreads the new ScreenSize parameters into almost every widget and provider method; consider using a single Provider or InheritedWidget to hold the selected badge size so you don’t have to modify every signature and widget.
  • The Converters.messageTohex method has become extremely large with mixed responsibilities (emoji tags, char scaling, bitmap scaling); refactor by extracting emoji, character, and bitmap conversion into separate helper classes or private services to improve readability and testability.
  • BadgePaint (and other rendering code) still uses magic scaling factors like 0.93 and 0.5—extract these into named constants or compute them dynamically from width/height ratios to avoid unexpected layout issues on non-standard sizes.

Prompt for AI Agents
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.

Hey @sourcery-ai ,
If every animation, effect, data transformation, and BLE message depends directly on ScreenSize, then yes — passing it explicitly ensures:

  • Clear contract of what a function needs
  • Easier to debug misalignment between expected and actual sizes
  • Avoids hidden side-effects from global access

Isn't It ?

@samruddhi-Rahegaonkar samruddhi-Rahegaonkar force-pushed the issue1344 branch 3 times, most recently from 1038c33 to e334dbe Compare June 28, 2025 08:59
@samruddhi-Rahegaonkar samruddhi-Rahegaonkar marked this pull request as draft June 28, 2025 09:21
@samruddhi-Rahegaonkar samruddhi-Rahegaonkar force-pushed the issue1344 branch 2 times, most recently from 4d3d10a to 856c79e Compare June 28, 2025 09:42
@github-actions

This comment was marked as outdated.

@samruddhi-Rahegaonkar samruddhi-Rahegaonkar marked this pull request as ready for review June 28, 2025 11:35
Copy link
Copy Markdown
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 @samruddhi-Rahegaonkar - I've reviewed your changes - here's some feedback:

  • Consider centralizing the selected ScreenSize in a provider or InheritedWidget so you don’t have to prop-drill it through every widget and method call.
  • The Converters class now mixes text parsing, bitmap scaling, emoji handling, and hex formatting—splitting it into focused services (e.g. TextConverter, ImageConverter) will improve readability and testability.
  • There are multiple bitmap scaling and trimming routines (_scaleBitmapToBadgeSize, _scaleTextCharacterToBadgeSize, convertBitmapToLEDHex, etc.); consolidating them into shared utilities will reduce duplication and ensure consistent behavior.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider centralizing the selected ScreenSize in a provider or InheritedWidget so you don’t have to prop-drill it through every widget and method call.
- The Converters class now mixes text parsing, bitmap scaling, emoji handling, and hex formatting—splitting it into focused services (e.g. TextConverter, ImageConverter) will improve readability and testability.
- There are multiple bitmap scaling and trimming routines (_scaleBitmapToBadgeSize, _scaleTextCharacterToBadgeSize, convertBitmapToLEDHex, etc.); consolidating them into shared utilities will reduce duplication and ensure consistent behavior.

## Individual Comments

### Comment 1
<location> `lib/providers/draw_badge_provider.dart:25` </location>
<code_context>
-        }
+    final rows = _drawViewGrid.length;
+    final cols = _drawViewGrid.isNotEmpty ? _drawViewGrid[0].length : 0;
+    for (int i = 0; i < rows && i < badgeData.length; i++) {
+      for (int j = 0; j < cols && j < badgeData[0].length; j++) {
+        _drawViewGrid[i][j] = badgeData[i][j];
</code_context>

<issue_to_address>
updateDrawViewGrid only copies overlapping regions, which may leave parts of the grid unchanged.

If badgeData is smaller than the grid, leftover cells may show outdated data. Please clear or reset all grid cells before copying new values.
</issue_to_address>

### Comment 2
<location> `lib/virtualbadge/view/badge_paint.dart:50` </location>
<code_context>
+    final int rows = grid.length;
+
+    // Adjust cell size to fit all pixels inside the badge area
+    final double cellWidth = badgeWidth / (cols * 0.93);
+    final double cellHeight = badgeHeight / rows;
+    final double cellSize = math.min(cellWidth, cellHeight);
</code_context>

<issue_to_address>
The cell width uses a 0.93 scaling factor, which may not be intuitive.

Please document the choice of 0.93 or make it a configurable parameter to improve clarity and adaptability.
</issue_to_address>

### Comment 3
<location> `lib/virtualbadge/view/badge_paint.dart:97` </location>
<code_context>
-  bool shouldRepaint(covariant CustomPainter oldDelegate) {
-    return true;
-  }
+  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
 }
</code_context>

<issue_to_address>
shouldRepaint always returns true, which may cause unnecessary repaints.

Compare the old and new grid values in shouldRepaint to avoid unnecessary repaints and improve performance.

Suggested implementation:

```
  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    if (oldDelegate is! YourPainterClassName) return true;
    return oldDelegate.grid != grid;
  }
}

```

- Replace `YourPainterClassName` with the actual name of your CustomPainter subclass.
- Ensure that `grid` is a field of your painter class and that it implements `==` properly (e.g., use `ListEquality` from `collection` if it's a List).
- If `grid` is a complex object, you may need to implement or use a deep equality check.
</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 thread lib/providers/draw_badge_provider.dart Outdated
Comment thread lib/virtualbadge/view/badge_paint.dart Outdated
Comment thread lib/virtualbadge/view/badge_paint.dart Outdated
@nope3472
Copy link
Copy Markdown
Contributor

hey @samruddhi-Rahegaonkar can you resolve the conflicts.

@samruddhi-Rahegaonkar
Copy link
Copy Markdown
Member Author

@nope3472 I will resolve it by end of the day.

@samruddhi-Rahegaonkar
Copy link
Copy Markdown
Member Author

@nope3472 will you please test font style feature on this it is not properly showing on my side.

@mariobehling
Copy link
Copy Markdown
Member

@sourcery-ai review again

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Oct 13, 2025

Sorry @mariobehling, your pull request is larger than the review limit of 150000 diff characters

@mariobehling mariobehling requested a review from Copilot October 13, 2025 15:11
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces comprehensive support for multiple LED badge screen sizes by creating a dynamic sizing system that replaces hardcoded dimensions throughout the application. The changes enable users to select from multiple badge configurations (44x11, 64x16, 128x32) through dropdown interfaces.

  • Introduced ScreenSize model with predefined badge dimensions and size selection UI components
  • Refactored core providers and utilities to accept dynamic width/height parameters instead of hardcoded values
  • Updated converters, byte array utilities, and rendering logic to handle arbitrary badge dimensions with proper scaling

Reviewed Changes

Copilot reviewed 34 out of 34 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
lib/bademagic_module/models/screen_size.dart Defines ScreenSize model and supported badge dimensions
test/data_to_bytearray_converter_test.dart Updates test methods to include badgeHeight parameter for new converter signature
test/converters_test.dart Adds ScreenSize parameter and expected hex values for converter testing
lib/providers/animation_badge_provider.dart Adds grid initialization with ScreenSize and dynamic dimension handling
lib/view/homescreen.dart Integrates ScreenSize selection dropdown and propagates size throughout animation pipeline
lib/virtualbadge/view/draw_badge.dart Updates drawing logic to use dynamic badge dimensions from ScreenSize
lib/providers/saved_badge_provider.dart Adds height/width parameters to badge saving and loading methods

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread lib/virtualbadge/view/draw_badge.dart Outdated
Comment thread lib/bademagic_module/utils/byte_array_utils.dart
Comment thread lib/view/save_badge_screen.dart
Comment thread lib/view/homescreen.dart Outdated
samruddhi-Rahegaonkar and others added 2 commits October 14, 2025 18:33
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@adityastic
Copy link
Copy Markdown
Collaborator

Hey @samruddhi-Rahegaonkar this PR has too many unrelated changes. Ideally adding support to multiple badge sizes should be tied to the badge unique identifier and allowing users to select a new badge which changes it's height and width accordingly. I don't know why these many changes are involved.

@samruddhi-Rahegaonkar
Copy link
Copy Markdown
Member Author

@adityastic I will make fresh PR for this issue.

@mariobehling
Copy link
Copy Markdown
Member

Thank you! Closing this PR and looking forward to a fresh PR.

Small process note.

We have automatic Copilot PR reviews enabled on this repository. These reviews are only triggered if the contributor has GitHub Copilot enabled and an active license on their own account.

Please enable Copilot in your GitHub settings if you have access. In many regions, free licenses are available through educational institutions or developer programs. Enabling Copilot helps us speed up the auto review process and reduces manual review overhead for the core team.

The team will review your PR. Thank you for your contribution and cooperation.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 34 out of 34 changed files in this pull request and generated 15 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/view/homescreen.dart

@override
void initState() {
super.initState();
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

HomeScreen implements WidgetsBindingObserver and defines didChangeAppLifecycleState, but initState no longer calls WidgetsBinding.instance.addObserver(this). As a result, lifecycle callbacks won’t run while dispose still removes the observer. Add the observer registration in initState (or remove the observer mixin/logic).

Suggested change
super.initState();
super.initState();
WidgetsBinding.instance.addObserver(this);

Copilot uses AI. Check for mistakes.
Comment thread lib/view/homescreen.dart
Comment on lines +435 to +436
TransitionTab(selectedSize: _selectedSize),
AnimationTab(selectedSize: _selectedSize),
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

TabBar labels don’t match the TabBarView child order: the tab labeled “Animation” shows TransitionTab and the tab labeled “Transition” shows AnimationTab. Reorder either the TabBar tabs or the TabBarView children so indices align.

Suggested change
TransitionTab(selectedSize: _selectedSize),
AnimationTab(selectedSize: _selectedSize),
AnimationTab(selectedSize: _selectedSize),
TransitionTab(selectedSize: _selectedSize),

Copilot uses AI. Check for mistakes.
Comment thread lib/view/homescreen.dart
Comment on lines +645 to +654
if (state == AppLifecycleState.resumed) {
inlineimagecontroller.clear();
previousText = '';
animationProvider.stopAllAnimations();
animationProvider.initializeAnimation();
if (mounted) setState(() {});
} else if (state == AppLifecycleState.paused ||
state == AppLifecycleState.inactive) {
animationProvider.stopAnimation();
}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

On app resume, didChangeAppLifecycleState clears the text controller and resets previousText, which will discard the user’s in-progress message when returning from background. Consider restoring the previous controller text (or avoiding mutation) and just restarting animations as needed.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +3
// ignore_for_file: invalid_use_of_visible_for_testing_member

import 'package:badgemagic/bademagic_module/models/screen_size.dart';
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

This file disables invalid_use_of_visible_for_testing_member, but the code is actually calling a protected member (notifyListeners) directly. Prefer removing the file-level ignore and exposing a public method on DrawBadgeProvider to trigger updates, rather than calling notifyListeners externally.

Copilot uses AI. Check for mistakes.
Comment on lines +237 to +238
int badgeWidth,
int badgeHeight) async {
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

updateBadgeData’s parameters are ordered as (badgeWidth, badgeHeight), but most other call sites and Data serialization treat them as (height, width). This mismatch is already causing swapped arguments from callers. Consider changing the method signature to (badgeHeight, badgeWidth) and updating all calls to keep ordering consistent across the codebase.

Suggested change
int badgeWidth,
int badgeHeight) async {
int badgeHeight,
int badgeWidth) async {

Copilot uses AI. Check for mistakes.
Comment on lines +105 to 115
void commitGridUpdate() {
_pushToUndoStack();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
_drawViewGrid[i][j] =
(j < badgeData[0].length) ? badgeData[i][j] : false;
if (_previewGrid[i][j]) {
_drawViewGrid[i][j] = true;
}
}
}
clearPreviewGrid();
notifyListeners();
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

commitGridUpdate currently sets affected cells to true whenever _previewGrid is true. Because preview cells are set to isDrawing, erase previews write false and will never be applied (erasing with shapes won’t work). Apply the preview value to _drawViewGrid (or apply isDrawing) instead of forcing true.

Copilot uses AI. Check for mistakes.
Comment on lines 184 to 194
for (int i = 0; i < text.length; i++) {
String char = text[i];
bool hasDescender = "ypgqj".contains(char);
final matrixData = await renderTextToMatrix(char, style,
rows: 11, hasDescender: hasDescender);
targetWidth: size.width,
targetHeight: size.height,
hasDescender: hasDescender);
List<List<bool>> charMatrix = matrixData['matrix'];
for (int row = 0; row < 11; row++) {
for (int row = 0; row < size.height; row++) {
combinedMatrix[row].addAll(charMatrix[row]);
}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

Custom font rendering renders each character using targetWidth = size.width and then concatenates the full-width matrices. This makes every character as wide as the whole badge and causes the combinedMatrix to explode in width. renderTextToMatrix should render each character at its natural width (or a fixed glyph width) and only scale to targetHeight; alternatively render the entire message once and then segment to 8px columns.

Copilot uses AI. Check for mistakes.
Comment thread lib/view/homescreen.dart
Comment on lines +513 to +514
_selectedSize.height,
_selectedSize.width,
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

updateBadgeData is declared as (badgeWidth, badgeHeight) in SavedBadgeProvider, but this call passes (_selectedSize.height, _selectedSize.width). This will swap stored width/height for updated badges. Pass width first, height second (or adjust the provider signature to match the rest of the codebase).

Suggested change
_selectedSize.height,
_selectedSize.width,
_selectedSize.width,
_selectedSize.height,

Copilot uses AI. Check for mistakes.
Comment on lines +169 to +183
builder: (context) => AlertDialog(
title: const Text('Edit Badge'),
content: const Text(
'Do you want to edit this badge?'),
actions: [
TextButton(
onPressed: () =>
Navigator.pop(context, false),
child: const Text('No'),
),
TextButton(
onPressed: () =>
Navigator.pop(context, true),
child: const Text('Yes'),
),
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

The edit confirmation dialog uses hard-coded English strings ('Edit Badge', 'Do you want to edit this badge?', 'No', 'Yes'). These should be localized via l10n (and ideally reused across the app) to avoid i18n regressions.

Copilot uses AI. Check for mistakes.
Comment on lines 245 to +263
ANDROID_EMULATOR_API: ${{ env.ANDROID_EMULATOR_API }}
ANDROID_EMULATOR_ARCH: ${{ env.ANDROID_EMULATOR_ARCH }}

screenshots-iphone:
name: Screenshots (iPhone)
screenshots-ios:
name: Screenshots (iOS)
runs-on: macos-latest
timeout-minutes: 30
steps:
- name: Set up Xcode
uses: maxim-lobanov/setup-xcode@v1.6.0
with:
xcode-version: latest-stable

- uses: actions/checkout@v5
- uses: actions/checkout@v4

- name: iPhone Screenshot Workflow
uses: ./.github/actions/screenshot-iphone
with:
IPHONE_DEVICE_MODEL: ${{ env.IPHONE_DEVICE_MODEL }}

screenshots-ipad:
name: Screenshots (iPad)
runs-on: macos-latest
timeout-minutes: 30
steps:
- name: Set up Xcode
uses: maxim-lobanov/setup-xcode@v1.6.0
with:
xcode-version: latest-stable

- uses: actions/checkout@v5

- name: iPad Screenshot Workflow
uses: ./.github/actions/screenshot-ipad
with:
IPAD_DEVICE_MODEL: ${{ env.IPAD_DEVICE_MODEL }}

debian:
name: Debian Flutter Build
needs: common
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: Debian Workflow
uses: ./.github/actions/debian
with:
VERSION_NAME: ${{ needs.common.outputs.VERSION_NAME }}
VERSION_CODE: ${{ needs.common.outputs.VERSION_CODE }}

- name: Upload Debian Build
uses: actions/upload-artifact@v4
with:
name: Debian Build
path: build/linux/x64/release/bundle/

- name: Push Debian Build to app branch
shell: bash
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"

git clone --branch=app https://${{ github.repository_owner }}:${{ github.token }}@github.com/${{ github.repository }} app
cd app
branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}
cp -r ../build/linux/x64/release/bundle/* .
git checkout --orphan temporary
git add --all
git commit -m "[Auto] Update Debian build from $branch ($(date +%Y-%m-%d.%H:%M:%S))"
git branch -D app
git branch -m app
git push --force origin app

macos:
name: macOS Flutter Build
needs: common
runs-on: macos-latest
steps:
- uses: actions/checkout@v5

- name: macOS Workflow
uses: ./.github/actions/macos
with:
VERSION_NAME: ${{ needs.common.outputs.VERSION_NAME }}
VERSION_CODE: ${{ needs.common.outputs.VERSION_CODE }}

- name: Upload macOS Build
uses: actions/upload-artifact@v4
with:
name: macOS Build
path: build/macos/Build/Products/Release/

- name: Push macOS Build to app branch
shell: bash
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"

git clone --branch=app https://${{ github.repository_owner }}:${{ github.token }}@github.com/${{ github.repository }} app
cd app
branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}

# Copy all macOS build artifacts to root
cp -r ../build/macos/Build/Products/Release/* .

git checkout --orphan temporary
git add --all
git commit -m "[Auto] Update macOS build from $branch ($(date +%Y-%m-%d.%H:%M:%S))"
git branch -D app
git branch -m app
git push --force origin app


windows:
name: Windows Flutter Build
needs: common
runs-on: windows-latest
steps:
- uses: actions/checkout@v5

- name: Windows Workflow
uses: ./.github/actions/windows
- name: iOS Screenshot Workflow
uses: ./.github/actions/screenshot-ios
with:
VERSION_NAME: ${{ needs.common.outputs.VERSION_NAME }}
VERSION_CODE: ${{ needs.common.outputs.VERSION_CODE }}

- name: Upload Windows Build
uses: actions/upload-artifact@v4
with:
name: Windows Build
path: build/windows/x64/runner/Release/

- name: Push Windows Build to app branch
shell: bash
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"

git clone --branch=app https://${{ github.repository_owner }}:${{ github.token }}@github.com/${{ github.repository }} app
cd app
branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}

# Copy all Windows build artifacts to root
cp -r ../build/windows/x64/runner/Release/* .

git checkout --orphan temporary
git add --all
git commit -m "[Auto] Update Windows build from $branch ($(date +%Y-%m-%d.%H:%M:%S))"
git branch -D app
git branch -m app
git push --force origin app

IPHONE_DEVICE_MODEL: ${{ env.IPHONE_DEVICE_MODEL }}
IPAD_DEVICE_MODEL: ${{ env.IPAD_DEVICE_MODEL }} No newline at end of file
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

This workflow refactor consolidates the iOS screenshot jobs (and removes several previously defined jobs in this file). If those removed jobs (e.g., separate iPhone/iPad screenshots and/or desktop build jobs) are still required for releases/CI coverage, they should be restored; otherwise please update the PR description to explicitly call out the CI job removals to avoid surprises.

Copilot uses AI. Check for mistakes.
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.

Support User-Selectable LED Badge Screen Sizes in App

7 participants