Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added the right scroll animation #1000

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed assets/icons/postman collections.zip
Binary file not shown.
53 changes: 53 additions & 0 deletions lib/bademagic_module/utils/byte_array_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,56 @@ List<int> hexStringToByteArray(String hexString) {
logger.d(data.length);
return data;
}

List<List<int>> byteArrayToBinaryArray(List<int> byteArray) {
List<List<int>> binaryArray = List.generate(11, (_) => []);

int rowIndex = 0;
for (int byte in byteArray) {
List<int> binaryRepresentation = [];
for (int i = 7; i >= 0; i--) {
binaryRepresentation.add((byte >> i) & 1);
}

binaryArray[rowIndex].addAll(binaryRepresentation);

rowIndex = (rowIndex + 1) % 11;
}

logger.d(
"binaryArray: $binaryArray"); // Use print instead of logger for standalone example
return binaryArray;
}

String hexToBin(String hex) {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (performance): Optimize hexToBin function for better performance

The current implementation using BigInt might be inefficient for large inputs. Consider implementing a direct hex to binary conversion using bitwise operations or a lookup table for better performance.

String hexToBin(String hex) {
  final lookup = {
    '0': '0000', '1': '0001', '2': '0010', '3': '0011',
    '4': '0100', '5': '0101', '6': '0110', '7': '0111',
    '8': '1000', '9': '1001', 'a': '1010', 'b': '1011',
    'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111'
  };
  return hex.toLowerCase().split('').map((c) => lookup[c]!).join();
}

// Convert hex to binary string
String binaryString = BigInt.parse(hex, radix: 16).toRadixString(2);

// Pad the binary string with leading zeros if necessary to ensure it's a multiple of 8 bits
int paddingLength = (8 - (binaryString.length % 8)) % 8;
binaryString = binaryString.padLeft(binaryString.length + paddingLength, '0');
logger.d("binaryString: $binaryString");
return binaryString;
}

List<List<int>> binaryStringTo2DList(String binaryString) {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider refactoring binaryStringTo2DList for improved readability and efficiency

The current implementation uses nested loops with single-letter variables, which can be hard to follow. Consider using more descriptive variable names and simplifying the logic. You might also want to add error handling for cases where the input string length doesn't match the expected size.

List<List<int>> binaryStringTo2DList(String binaryString) {
  const int expectedLength = 11 * 7;
  if (binaryString.length != expectedLength) {
    throw ArgumentError('Invalid binary string length. Expected $expectedLength, got ${binaryString.length}');
  }
  final int maxHeight = 11;
  final List<List<int>> binary2DList = List.generate(maxHeight, (_) => []);

int maxHeight = 11;
List<List<int>> binary2DList = List.generate(maxHeight, (_) => []);

for (int x = 0; x < binaryString.length; x++) {
int a = 0;
for (int y = a; y < 11; y++) {
for (int z = 0; z < 8; z++) {
binary2DList[y].add(int.parse(binaryString[x++]));
if (x >= binaryString.length) {
break;
}
}
if (x >= binaryString.length) {
break;
}
}
}
logger.d("binary2DList: $binary2DList");
return binary2DList;
}
23 changes: 19 additions & 4 deletions lib/bademagic_module/utils/converters.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:badgemagic/bademagic_module/utils/byte_array_utils.dart';
import 'package:badgemagic/bademagic_module/utils/data_to_bytearray_converter.dart';
import 'package:badgemagic/bademagic_module/utils/file_helper.dart';
import 'package:badgemagic/bademagic_module/utils/image_utils.dart';
import 'package:badgemagic/providers/badgeview_provider.dart';
import 'package:badgemagic/providers/imageprovider.dart';
import 'package:get_it/get_it.dart';

Expand All @@ -12,6 +13,7 @@ class Converters {
DataToByteArrayConverter converter = DataToByteArrayConverter();
ImageUtils imageUtils = ImageUtils();
FileHelper fileHelper = FileHelper();
DrawBadgeProvider badgeList = GetIt.instance.get<DrawBadgeProvider>();

int controllerLength = 0;

Expand All @@ -23,10 +25,8 @@ class Converters {
var key = controllerData.imageCache.keys.toList()[index];
if (key is List) {
String filename = key[0];
logger.d("Filename: $filename");
List<List<int>>? image = await fileHelper.readFromFile(filename);
logger.d("Image: $image");
hexStrings = convertBitmapToLEDHex(image!, true);
hexStrings += convertBitmapToLEDHex(image!, true);
x += 5;
} else {
List<String> hs =
Expand All @@ -43,6 +43,22 @@ class Converters {
return hexStrings;
}

void badgeAnimation(String message) async {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Separate concerns in badgeAnimation function

This function is mixing data processing with UI updates. Consider splitting it into two functions: one for data conversion and another for updating the UI. This will improve maintainability and adhere better to the principle of separation of concerns.

Future<List<List<int>>> convertMessageToMatrix(String message) async {
  // Implementation for converting message to matrix
}

void updateBadgeUI(List<List<int>> matrix) async {
  // Implementation for updating the UI with the matrix
}

void badgeAnimation(String message) async {
  final matrix = await convertMessageToMatrix(message);
  updateBadgeUI(matrix);
}

if (message == "") {
//geerate a 2d list with all values as 0
List<List<int>> image =
List.generate(11, (i) => List.generate(44, (j) => 0));
badgeList.setNewGrid(image);
badgeList.startAnimation();
} else {
List<String> hexStrings = await messageTohex(message);
List<int> byteArray = hexStringToByteArray(hexStrings.join());
List<List<int>> binaryArray = byteArrayToBinaryArray(byteArray);
badgeList.setNewGrid(binaryArray);
badgeList.startAnimation();
}
}

//function to convert the bitmap to the LED hex format
//it takes the 2D list of pixels and converts it to the LED hex format
static List<String> convertBitmapToLEDHex(
Expand Down Expand Up @@ -145,7 +161,6 @@ class Converters {

allHexs.add(lineHex.toString()); // Store completed hexadecimal line
}
logger.d("All hexs: $allHexs");
return allHexs; // Return list of hexadecimal strings
}
}
2 changes: 0 additions & 2 deletions lib/bademagic_module/utils/image_utils.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'dart:ui' as ui;
import 'dart:ui';
import 'package:badgemagic/bademagic_module/utils/byte_array_utils.dart';
import 'package:badgemagic/bademagic_module/utils/converters.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Expand Down Expand Up @@ -222,7 +221,6 @@ class ImageUtils {
}
}
}
logger.d("Pixel Array generated = $pixelArray");
return Converters.convertBitmapToLEDHex(pixelArray, false);
}
}
32 changes: 32 additions & 0 deletions lib/badge_animation/ani_right.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'package:badgemagic/badge_animation/animation_abstract.dart';

class RightAnimation extends BadgeAnimation {
@override
void animation(
List<List<bool>> grid,
List<List<int>> newGrid,
int animationIndex,
bool validMarquee,
bool flashLEDOn,
int currentcountFrame,
int i,
int j,
int newHeight,
int newWidth,
int badgeHeight,
int badgeWidth) {
// Calculate the scroll offset to move from left to right
int scrollOffset = animationIndex % (newWidth + badgeWidth);

// Get the corresponding column in the new grid based on the reversed scroll position
int sourceCol = newWidth - scrollOffset + j;

// If sourceCol is within bounds of the new grid, display it, else blank space
if (sourceCol >= 0 && sourceCol < newWidth) {
grid[i][j] =
validMarquee || flashLEDOn && newGrid[i % newHeight][sourceCol] == 1;
} else {
validMarquee ? grid[i][j] = true : grid[i][j] = false;
}
}
}
33 changes: 33 additions & 0 deletions lib/badge_animation/anim_left.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:badgemagic/badge_animation/animation_abstract.dart';

class LeftAnimation extends BadgeAnimation {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider unifying animation logic to reduce code duplication

The LeftAnimation and RightAnimation classes have very similar logic. Consider creating a base class or a utility function that both can use, parameterizing the differences. This would reduce code duplication and make it easier to maintain and extend the animation system.

abstract class DirectionalAnimation extends BadgeAnimation {
  final bool isLeftDirection;

  DirectionalAnimation({required this.isLeftDirection});

  // Common animation logic goes here
}

class LeftAnimation extends DirectionalAnimation {
  LeftAnimation() : super(isLeftDirection: true);

@override
void animation(
List<List<bool>> grid,
List<List<int>> newGrid,
int animationIndex,
bool validMarquee,
bool flashLEDOn,
int currentcountFrame,
int i,
int j,
int newHeight,
int newWidth,
int badgeHeight,
int badgeWidth) {
// Calculate how much of the new grid is currently visible in the grid
int scrollOffset = animationIndex % (newWidth + badgeWidth);

// Get the corresponding column in the new grid based on the scroll position
int sourceCol = j + scrollOffset - badgeWidth;

// If sourceCol is negative, display blank space (off-screen part of the grid)
if (sourceCol >= 0 && sourceCol < newWidth) {
// Ensure flashLEDOn and validMarquee effects are applied
grid[i][j] =
validMarquee || flashLEDOn && newGrid[i % newHeight][sourceCol] == 1;
} else {
validMarquee ? grid[i][j] = true : grid[i][j] = false;
}
}
}
15 changes: 15 additions & 0 deletions lib/badge_animation/animation_abstract.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
abstract class BadgeAnimation {
void animation(
List<List<bool>> grid,
List<List<int>> newGrid,
int animationIndex,
bool validMarquee,
bool flashLEDOn,
int currentcountFrame,
int i,
int j,
int newHeight,
int newWidth,
int badgeHeight,
int badgeWidth);
}
12 changes: 12 additions & 0 deletions lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,15 @@ const String aniRight = 'assets/animations/ic_anim_right.gif';
const String effFlash = 'assets/effects/ic_effect_flash.gif';
const String effInvert = 'assets/effects/ic_effect_invert.gif';
const String effMarque = 'assets/effects/ic_effect_marquee.gif';

//constants for the animation speed
const Duration aniBaseSpeed = Duration(microseconds: 200000); // in uS
const Duration aniMarqueSpeed = Duration(microseconds: 100000); // in uS
const Duration aniFlashSpeed = Duration(microseconds: 500000); // in uS

// Function to calculate animation speed based on speed level
int aniSpeedStrategy(int speedLevel) {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider using an enum for speed levels

Instead of using raw integers for speed levels, consider defining an enum. This would make the code more type-safe and self-documenting.

enum SpeedLevel { slow, medium, fast, veryFast }

int aniSpeedStrategy(SpeedLevel level) {
  final int speedFactor = level.index;
  return aniBaseSpeed.inMicroseconds - (speedFactor * aniBaseSpeed.inMicroseconds ~/ 8);
}

int speedInMicroseconds = aniBaseSpeed.inMicroseconds -
(speedLevel * aniBaseSpeed.inMicroseconds ~/ 8);
return speedInMicroseconds;
}
2 changes: 1 addition & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:badgemagic/providers/cardsprovider.dart';
import 'package:badgemagic/providers/drawbadge_provider.dart';
import 'package:badgemagic/providers/badgeview_provider.dart';
import 'package:badgemagic/providers/getitlocator.dart';
import 'package:badgemagic/providers/imageprovider.dart';
import 'package:badgemagic/view/draw_badge_screen.dart';
Expand Down
Loading
Loading