@@ -2,64 +2,167 @@ import 'package:badgemagic/badge_animation/animation_abstract.dart';
2
2
3
3
class AniAnimation extends BadgeAnimation {
4
4
@override
5
- void processAnimation (int badgeHeight, int badgeWidth, int animationIndex,
6
- List <List <bool >> processGrid, List <List <bool >> canvas) {
7
- int newWidth = processGrid[0 ].length;
8
- int newHeight = processGrid.length;
9
- int verticalOffset = (badgeHeight - newHeight) ~ / 2 ;
10
- int displayWidth = newWidth > badgeWidth ? badgeWidth : newWidth;
11
- int horizontalOffset = (badgeWidth - displayWidth) ~ / 2 ;
12
- var totalAnimationLength = badgeWidth;
13
- int frame = animationIndex % totalAnimationLength;
14
- var firstHalf = frame < badgeWidth ~ / 2 ;
15
- var secondHalf = frame >= badgeWidth ~ / 2 ;
5
+ void processAnimation (
6
+ int badgeHeight,
7
+ int badgeWidth,
8
+ int animationIndex,
9
+ List <List <bool >> processGrid,
10
+ List <List <bool >> canvas,
11
+ ) {
12
+ if (processGrid.isEmpty ||
13
+ processGrid.any ((row) => row.length != processGrid[0 ].length)) {
14
+ throw ArgumentError (
15
+ 'processGrid must be a non-empty rectangular 2D list' ,
16
+ );
17
+ }
18
+
19
+ int newGridHeight = processGrid.length;
20
+ int newGridWidth = processGrid[0 ].length;
21
+
22
+ if (canvas.length < badgeHeight ||
23
+ canvas.any ((row) => row.length < badgeWidth)) {
24
+ throw ArgumentError (
25
+ 'canvas must have at least $badgeHeight rows and $badgeWidth columns' ,
26
+ );
27
+ }
16
28
29
+ // Clear canvas first
17
30
for (int i = 0 ; i < badgeHeight; i++ ) {
18
31
for (int j = 0 ; j < badgeWidth; j++ ) {
19
- bool lineShow = false ;
20
- bool bitmapShowcenter = false ;
21
- bool bitmapShowOut = false ;
32
+ canvas[i][j] = false ;
33
+ }
34
+ }
22
35
23
- int sourceRow = i - verticalOffset;
24
- int sourceCol = j - horizontalOffset;
36
+ // Find word boundaries by detecting spaces (multiple empty columns)
37
+ List <Map <String , int >> words =
38
+ _findWords (processGrid, newGridHeight, newGridWidth);
39
+
40
+ if (words.isEmpty) {
41
+ // If no words found, show the entire grid
42
+ _displaySegment (processGrid, canvas, 0 , newGridWidth, badgeHeight,
43
+ badgeWidth, newGridHeight);
44
+ return ;
45
+ }
25
46
26
- bool isWithinNewGrid = sourceRow >= 0 &&
27
- sourceRow < newHeight &&
28
- sourceCol >= 0 &&
29
- sourceCol < displayWidth;
47
+ // Determine which word to show based on animation index
48
+ int frameDisplayDuration =
49
+ 30 ; // Adjust this to control how long each word is shown
50
+ int currentWordIndex =
51
+ (animationIndex ~ / frameDisplayDuration) % words.length;
30
52
31
- int leftCenterCol = badgeWidth ~ / 2 - 1 ;
32
- int rightCenterCol = badgeWidth ~ / 2 ;
53
+ // Get start and end positions for current word
54
+ int wordStart = words[currentWordIndex]['start' ]! ;
55
+ int wordEnd = words[currentWordIndex]['end' ]! ;
33
56
34
- int maxDistance = leftCenterCol;
57
+ // Display the current word
58
+ _displaySegment (processGrid, canvas, wordStart, wordEnd, badgeHeight,
59
+ badgeWidth, newGridHeight);
60
+ }
35
61
36
- int currentAnimationIndex = animationIndex % (maxDistance + 1 );
62
+ List <Map <String , int >> _findWords (
63
+ List <List <bool >> grid, int height, int width) {
64
+ List <Map <String , int >> words = [];
65
+ int minSpaceWidth =
66
+ 3 ; // Minimum number of empty columns to consider as word separator
37
67
38
- int leftColPos = leftCenterCol - currentAnimationIndex ;
39
- int rightColPos = rightCenterCol + currentAnimationIndex ;
68
+ int wordStart = - 1 ;
69
+ int emptyColumnCount = 0 ;
40
70
41
- if (leftColPos < 0 ) leftColPos += badgeWidth;
42
- if (rightColPos >= badgeWidth) rightColPos -= badgeWidth ;
71
+ for ( int col = 0 ; col < width; col ++ ) {
72
+ bool hasPixel = false ;
43
73
44
- if (j == leftColPos || j == rightColPos) {
45
- lineShow = true ;
46
- } else {
47
- lineShow = false ;
74
+ // Check if this column has any pixels
75
+ for (int row = 0 ; row < height; row++ ) {
76
+ if (grid[row][col]) {
77
+ hasPixel = true ;
78
+ break ;
48
79
}
80
+ }
49
81
50
- if (firstHalf) {
51
- if (isWithinNewGrid && j > leftColPos && j < rightColPos) {
52
- bitmapShowcenter = processGrid[sourceRow][sourceCol];
53
- }
82
+ if (hasPixel) {
83
+ // This column has content
84
+ if (wordStart == - 1 ) {
85
+ // Start of a new word
86
+ wordStart = col;
54
87
}
55
- if (secondHalf) {
56
- if (isWithinNewGrid && (j < leftColPos || j > rightColPos)) {
57
- bitmapShowOut = processGrid[sourceRow][sourceCol];
58
- }
88
+ emptyColumnCount = 0 ;
89
+ } else {
90
+ // This column is empty
91
+ emptyColumnCount++ ;
92
+
93
+ // If we have enough empty columns and we were in a word, end the word
94
+ if (emptyColumnCount >= minSpaceWidth && wordStart != - 1 ) {
95
+ words.add ({
96
+ 'start' : wordStart,
97
+ 'end' : col - emptyColumnCount + 1 ,
98
+ });
99
+ wordStart = - 1 ;
59
100
}
101
+ }
102
+ }
103
+
104
+ // Handle the last word if it extends to the end
105
+ if (wordStart != - 1 ) {
106
+ words.add ({
107
+ 'start' : wordStart,
108
+ 'end' : width,
109
+ });
110
+ }
60
111
61
- canvas[i][j] = (lineShow || bitmapShowOut || bitmapShowcenter);
112
+ return words;
113
+ }
114
+
115
+ void _displaySegment (
116
+ List <List <bool >> source,
117
+ List <List <bool >> canvas,
118
+ int startCol,
119
+ int endCol,
120
+ int badgeHeight,
121
+ int badgeWidth,
122
+ int sourceHeight) {
123
+ // Create temporary frame for the word
124
+ List <List <bool >> tempFrame = List .generate (
125
+ badgeHeight,
126
+ (_) => List .filled (badgeWidth, false ),
127
+ );
128
+
129
+ // Copy the word segment
130
+ int wordWidth = endCol - startCol;
131
+ for (int i = 0 ; i < badgeHeight && i < sourceHeight; i++ ) {
132
+ for (int j = 0 ; j < wordWidth && j < badgeWidth; j++ ) {
133
+ int sourceCol = startCol + j;
134
+ if (sourceCol < source[i].length) {
135
+ tempFrame[i][j] = source[i][sourceCol];
136
+ }
137
+ }
138
+ }
139
+
140
+ // Remove leading empty columns to left-align the word
141
+ int shiftLeftBy =
142
+ _countLeadingEmptyCols (tempFrame, badgeHeight, badgeWidth);
143
+
144
+ // Apply the shift and copy to canvas
145
+ for (int i = 0 ; i < badgeHeight; i++ ) {
146
+ for (int j = 0 ; j < badgeWidth; j++ ) {
147
+ int sourceCol = j + shiftLeftBy;
148
+ canvas[i][j] = sourceCol < badgeWidth ? tempFrame[i][sourceCol] : false ;
149
+ }
150
+ }
151
+ }
152
+
153
+ int _countLeadingEmptyCols (List <List <bool >> frame, int height, int width) {
154
+ for (int col = 0 ; col < width; col++ ) {
155
+ bool isColEmpty = true ;
156
+ for (int row = 0 ; row < height; row++ ) {
157
+ if (frame[row][col]) {
158
+ isColEmpty = false ;
159
+ break ;
160
+ }
161
+ }
162
+ if (! isColEmpty) {
163
+ return col;
62
164
}
63
165
}
166
+ return 0 ;
64
167
}
65
168
}
0 commit comments