Skip to content

Conversation

@nope3472
Copy link
Contributor

@nope3472 nope3472 commented Oct 11, 2025

Fixes #1470

Changes

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

Refine the snowflake animation to include dynamic horizontal scrolling with frame cycling and optimized frame limits, add bounds checks to avoid grid errors, and update the Hindi localization for 'animation'.

Bug Fixes:

  • Prevent out-of-bounds grid access in snowflake animation by adding row bounds checks

Enhancements:

  • Add horizontal scrolling support in the snowflake animation by cycling through frames based on grid width and clamping to a maximum of 8 frames
  • Calculate dynamic horizontal offsets and overall cycle positions to center and scroll the text correctly

Documentation:

  • Update Hindi translation for 'animation' from 'एनिमेशन' to 'डॉट-मैट्रिक्स'

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Oct 11, 2025

Reviewer's Guide

Enhanced SnowFlakeAnimation to support horizontal scrolling by partitioning the input grid into bounded frame cycles with clamp-based offsets and boundary checks; also updated the Hindi translation for the “animation” label.

Sequence diagram for horizontal scrolling in SnowFlakeAnimation

sequenceDiagram
participant "processAnimation()"
participant "processGrid"
participant "canvas"
"processAnimation()"->>"processGrid": Partition grid into frames
"processAnimation()"->>"canvas": Apply frame data with horizontal offset and boundary checks
"processAnimation()"->>"canvas": Update canvas for each animation phase
Loading

Class diagram for updated SnowFlakeAnimation scrolling logic

classDiagram
class BadgeAnimation
class SnowFlakeAnimation {
  +void processAnimation(int badgeHeight, int badgeWidth, int animationIndex, List<List<bool>> processGrid, List<List<bool>> canvas)
  -int newWidth
  -int newHeight
  -int framesCount
  -int snowflakeCycleLength
  -int maxFrames
  -int effectiveFramesCount
  -int totalCycleLength
  -int cyclePosition
  -int currentFrame
  -int startCol
  -int frame
  -int horizontalOffset
}
BadgeAnimation <|-- SnowFlakeAnimation
Loading

File-Level Changes

Change Details Files
Implement horizontal scrolling using frame partitioning and cycle calculations
  • Compute framesCount, maxFrames and effectiveFramesCount via clamp
  • Calculate totalCycleLength and cyclePosition from animationIndex
  • Derive currentFrame and startCol, replace old totalAnimationLength-based frame logic
lib/badge_animation/ani_snowflake.dart
Refine source column offset and enforce grid boundaries
  • Recalculate horizontalOffset using clamp to limit negative offsets
  • Update sourceCol to include startCol offset in rendering loops
  • Add row < newHeight checks before canvas assignments
lib/badge_animation/ani_snowflake.dart
Adjust Hindi localization for 'animation' label
  • Update translation in app_localizations_hi.dart from 'एनिमेशन' to 'डॉट-मैट्रिक्स'
  • Sync corresponding entry in app_hi.arb
lib/l10n/app_localizations_hi.dart
lib/l10n/app_hi.arb

Assessment against linked issues

Issue Objective Addressed Explanation
#1470 Update the app so the snowflake effect matches the badge behavior for one-word and two-word inputs.
#1470 Ensure the animation effect displays the same way on both app and badge. The PR only modifies the snowflake effect logic and does not address the animation effect or its consistency between app and badge.
#1470 Rename 'animation' on the transition view to 'Dot-Matrix' to avoid terminology confusion.

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 there - I've reviewed your changes - here's some feedback:

  • The cycle and frame‐position calculations in processAnimation are quite dense—consider refactoring into smaller helper methods or better‐named variables for clarity.
  • Verify that clamping horizontalOffset and effectiveFramesCount covers edge cases (e.g. when newWidth > badgeWidth) to avoid unexpected scroll offsets.
  • Changing the ‘animation’ translation to 'डॉट-मैट्रिक्स' shifts the meaning—ensure this matches the UI context or introduce a new L10n key instead of repurposing 'animation'.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The cycle and frame‐position calculations in processAnimation are quite dense—consider refactoring into smaller helper methods or better‐named variables for clarity.
- Verify that clamping horizontalOffset and effectiveFramesCount covers edge cases (e.g. when newWidth > badgeWidth) to avoid unexpected scroll offsets.
- Changing the ‘animation’ translation to 'डॉट-मैट्रिक्स' shifts the meaning—ensure this matches the UI context or introduce a new L10n key instead of repurposing 'animation'.

## Individual Comments

### Comment 1
<location> `lib/badge_animation/ani_snowflake.dart:10-11` </location>
<code_context>

-    int horizontalOffset = (badgeWidth - newWidth) ~/ 2;
+    // Calculate the total number of frames that fit the badge width
+    int framesCount = (newWidth / badgeWidth).ceil();
+
+    // Calculate the total animation length for one complete snowflake cycle
</code_context>

<issue_to_address>
**suggestion:** Consider using integer division for frame count calculation.

Floating-point division with ceil can cause off-by-one errors when newWidth isn't a multiple of badgeWidth. Integer division with rounding up, such as (newWidth + badgeWidth - 1) ~/ badgeWidth, is clearer and avoids this issue.

```suggestion
    // Calculate the total number of frames that fit the badge width using integer division rounding up
    int framesCount = (newWidth + badgeWidth - 1) ~/ badgeWidth;
```
</issue_to_address>

### Comment 2
<location> `lib/badge_animation/ani_snowflake.dart:35` </location>
<code_context>
+    // Get the frame within the current snowflake cycle
+    int frame = cyclePosition % snowflakeCycleLength;
+
+    int horizontalOffset = (badgeWidth - newWidth).clamp(0, badgeWidth) ~/ 2;

     bool phase1 = frame < badgeHeight * 4;
</code_context>

<issue_to_address>
**question:** Clamping horizontalOffset may mask layout issues.

Clamping prevents negative offsets but may conceal cases where newWidth exceeds badgeWidth, which could cause rendering issues. Please handle these cases explicitly or clarify the intended behavior in documentation.
</issue_to_address>

### Comment 3
<location> `lib/badge_animation/ani_snowflake.dart:51` </location>
<code_context>
+            int sourceCol = startCol + col - horizontalOffset;
             bool isWithinNewGrid = sourceCol >= 0 && sourceCol < newWidth;
-            if (isWithinNewGrid) {
+            if (isWithinNewGrid && row < newHeight) {
               canvas[fallPosition][col] = processGrid[row][sourceCol];
             }
</code_context>

<issue_to_address>
**nitpick:** Redundant row bounds check in inner loop.

If badgeHeight can exceed newHeight, validate badgeHeight against newHeight earlier to avoid redundant checks.
</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.

@nope3472 nope3472 changed the title fix: made the scrolling feature in snowflake effect fix: made the scrolling feature in snowflake effect Oct 11, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Oct 11, 2025

Build Status

Build workflow failed. Please check the logs for more information.

Screenshots

Not able to fetch screenshots.

Copy link
Member

@mariobehling mariobehling left a comment

Choose a reason for hiding this comment

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

Hi, I’ve reviewed this PR with the help of AI to speed up code analysis and ensure we catch technical issues early — please use AI tools as well (e.g., ChatGPT with code input or GitHub Copilot Chat) to check your code and reasoning next time. It really helps to find small mistakes faster and improves the review cycle.


⚠️ Must Fix Before Merge

1. Duplicate variable declarations

In ani_snowflake.dart, there are duplicate local variable declarations:

int frame = animationIndex % totalAnimationLength;
int horizontalOffset = (badgeWidth - newWidth) ~/ 2;
...
int frame = cyclePosition % snowflakeCycleLength;
int horizontalOffset = (badgeWidth - newWidth).clamp(0, badgeWidth) ~/ 2;

➡️ Fix: Remove the int keyword from the second declarations and just reuse the same variables:

frame = cyclePosition % snowflakeCycleLength;
horizontalOffset = (badgeWidth - newWidth).clamp(0, badgeWidth) ~/ 2;

Otherwise, this will not compile or could lead to unexpected shadowing.


2. Inefficient bounds checks and nested loops

The nested for loops use repetitive boundary checks (if (row < newHeight && col < newWidth) inside the inner loop).
➡️ Fix suggestion:
Clamp dimensions before looping:

final height = min(badgeHeight, newHeight);
final width = min(badgeWidth, newWidth);
for (int row = 0; row < height; row++) {
  for (int col = 0; col < width; col++) {
    ...
  }
}

This makes the loop more efficient and easier to read.


3. Horizontal offset logic may be hiding layout issues

You clamp horizontalOffset to [0, badgeWidth].
If newWidth > badgeWidth, this hides the fact that the image is wider and should scroll.
➡️ Suggestion: handle it explicitly:

if (newWidth > badgeWidth) {
  horizontalOffset = 0; // scrolling case
} else {
  horizontalOffset = (badgeWidth - newWidth) ~/ 2; // centering case
}

Add a short comment to document why clamping is not needed here.


4. Off-by-one risk in frame count

int framesCount = (newWidth / badgeWidth).ceil();
For safety and to stay in integer math, use:

int framesCount = (newWidth + badgeWidth - 1) ~/ badgeWidth;

This avoids rounding inconsistencies for narrow widths.


5. Clarify variables and add inline comments

Variables like totalCycleLength, cyclePosition, framesCount, and startCol interact in non-trivial ways.
Please add a short explanatory block at the top of the method describing:

  • how these values are derived,
  • how the cycle length is determined,
  • and why maxFrames = 8 is chosen.

Example:

// The snowflake animation scrolls horizontally across the display.
// totalCycleLength: number of frames per scroll cycle
// cyclePosition: current offset within the cycle
// maxFrames: upper bound to limit animation memory footprint

🧩 Internationalization

6. Manual edits in generated localization file

lib/l10n/app_localizations_hi.dart appears manually changed.
That file is auto-generated from .arb sources and will be overwritten.

➡️ Fix:
Revert manual edits, keep changes in .arb files only, then run:

flutter gen-l10n

to regenerate localized Dart files.


7. Inconsistent label rename

The key animation now maps to "Dot-Matrix" in English and Hindi, but not in other locales.
If it’s a global rename, update all .arb files.
If it’s local to one screen, use a new key (e.g. "dotMatrixLabel") instead of overwriting "animation" globally.


🧪 Minimal Test Plan

  1. Short and long text preview

    • Test texts that produce newWidth smaller, equal, and greater than badgeWidth.
    • Verify correct centering and horizontal scroll movement without clipping.
  2. Regression

    • Check that other effects (Laser, Picture, etc.) behave as before.
  3. Localization

    • Switch to Hindi and English; verify label shows as “Dot-Matrix”.
    • Re-run flutter gen-l10n and confirm no warnings.
  4. Badge parity

    • Send the same text to a physical badge and compare scroll speed and smoothness.

@samruddhi-Rahegaonkar
Copy link
Member

Looks Good to me!

@mariobehling mariobehling requested a review from Copilot October 13, 2025 14:51
Copy link

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 fixes the scrolling feature in the snowflake animation effect by implementing proper horizontal scrolling with frame cycling and adding bounds checks to prevent grid access errors.

Key changes include:

  • Enhanced snowflake animation with dynamic horizontal scrolling and frame management
  • Added bounds checking to prevent out-of-bounds grid access errors
  • Updated Hindi localization to change 'animation' translation from 'एनिमेशन' to 'डॉट-मैट्रिक्स'

Reviewed Changes

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

File Description
lib/badge_animation/ani_snowflake.dart Implements scrolling logic with frame cycling, dynamic offsets, and bounds checking
lib/l10n/app_localizations_hi.dart Updates Hindi translation for 'animation'
lib/l10n/app_hi.arb Updates Hindi localization resource for 'animation'
lib/l10n/app_en.arb Updates English localization from 'Animation' to 'Dot-Matrix'

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

@mariobehling mariobehling requested a review from Copilot October 31, 2025 14:18
Copy link

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 4 out of 4 changed files in this pull request and generated 3 comments.


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

"down": "Down",
"fixed": "Fixed",
"animation": "Animation",
"animation": "Dot-Matrix",
Copy link

Copilot AI Oct 31, 2025

Choose a reason for hiding this comment

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

Duplicate key 'animation' found in the localization file. This key appears at lines 65, 134, and 161. In JSON/ARB files, duplicate keys can cause unpredictable behavior as only the last occurrence will be used. Each key should be unique or the keys should be renamed to be more specific (e.g., 'animationMode', 'animationType', 'animationLabel').

Copilot uses AI. Check for mistakes.
"save": "सेव करें",
"speed": "स्पीड",
"animation": "एनिमेशन",
"animation": "डॉट-मैट्रिक्स",
Copy link

Copilot AI Oct 31, 2025

Choose a reason for hiding this comment

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

Duplicate key 'animation' found in the localization file. This key appears at lines 58, 123, and 150. In JSON/ARB files, duplicate keys can cause unpredictable behavior as only the last occurrence will be used. Each key should be unique or the keys should be renamed to be more specific (e.g., 'animationMode', 'animationType', 'animationLabel').

Copilot uses AI. Check for mistakes.
// Get the current position in the overall cycle
int cyclePosition = animationIndex % totalCycleLength;

// Determine which text section we're currently showing
Copy link

Copilot AI Oct 31, 2025

Choose a reason for hiding this comment

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

The comment mentions 'text section' but this is a snowflake animation. The comment should be updated to reflect the actual purpose, such as 'Determine which content frame we're currently showing'.

Suggested change
// Determine which text section we're currently showing
// Determine which content frame we're currently showing

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.

Fix Transition Effects and Rename "Animation" to "Dot-Matrix"

3 participants