1
1
import 'dart:developer' ;
2
+ import 'dart:math' ;
2
3
3
4
import 'package:flutter/foundation.dart' ;
4
5
import 'package:flutter/material.dart' ;
5
6
6
7
import 'package:flutter_gen/gen_l10n/l10n.dart' ;
8
+ import 'package:matrix/matrix.dart' ;
7
9
8
10
import '../../utils/bot_style.dart' ;
9
11
import 'it_shimmer.dart' ;
@@ -56,10 +58,12 @@ class Choice {
56
58
Choice ({
57
59
this .color,
58
60
required this .text,
61
+ this .isGold = false ,
59
62
});
60
63
61
64
final Color ? color;
62
65
final String text;
66
+ final bool isGold;
63
67
}
64
68
65
69
class ChoiceItem extends StatelessWidget {
@@ -86,45 +90,50 @@ class ChoiceItem extends StatelessWidget {
86
90
waitDuration: onLongPress != null
87
91
? const Duration (milliseconds: 500 )
88
92
: const Duration (days: 1 ),
89
- child: Container (
90
- margin: const EdgeInsets .all (2 ),
91
- padding: EdgeInsets .zero,
92
- decoration: isSelected
93
- ? BoxDecoration (
94
- borderRadius: const BorderRadius .all (Radius .circular (10 )),
95
- border: Border .all (
96
- color: entry.value.color ?? theme.colorScheme.primary,
97
- style: BorderStyle .solid,
98
- width: 2.0 ,
93
+ child: ChoiceAnimationWidget (
94
+ key: ValueKey (entry.value.text),
95
+ selected: entry.value.color != null ,
96
+ isGold: entry.value.isGold,
97
+ child: Container (
98
+ margin: const EdgeInsets .all (2 ),
99
+ padding: EdgeInsets .zero,
100
+ decoration: isSelected
101
+ ? BoxDecoration (
102
+ borderRadius: const BorderRadius .all (Radius .circular (10 )),
103
+ border: Border .all (
104
+ color: entry.value.color ?? theme.colorScheme.primary,
105
+ style: BorderStyle .solid,
106
+ width: 2.0 ,
107
+ ),
108
+ )
109
+ : null ,
110
+ child: TextButton (
111
+ style: ButtonStyle (
112
+ padding: MaterialStateProperty .all (
113
+ const EdgeInsets .symmetric (horizontal: 7 ),
114
+ ),
115
+ //if index is selected, then give the background a slight primary color
116
+ backgroundColor: MaterialStateProperty .all <Color >(
117
+ entry.value.color != null
118
+ ? entry.value.color! .withOpacity (0.2 )
119
+ : theme.colorScheme.primary.withOpacity (0.1 ),
120
+ ),
121
+ textStyle: MaterialStateProperty .all (
122
+ BotStyle .text (context),
123
+ ),
124
+ shape: MaterialStateProperty .all (
125
+ RoundedRectangleBorder (
126
+ borderRadius: BorderRadius .circular (10 ),
99
127
),
100
- )
101
- : null ,
102
- child: TextButton (
103
- style: ButtonStyle (
104
- padding: MaterialStateProperty .all (
105
- const EdgeInsets .symmetric (horizontal: 7 ),
106
- ),
107
- //if index is selected, then give the background a slight primary color
108
- backgroundColor: MaterialStateProperty .all <Color >(
109
- entry.value.color != null
110
- ? entry.value.color! .withOpacity (0.2 )
111
- : theme.colorScheme.primary.withOpacity (0.1 ),
112
- ),
113
- textStyle: MaterialStateProperty .all (
114
- BotStyle .text (context),
115
- ),
116
- shape: MaterialStateProperty .all (
117
- RoundedRectangleBorder (
118
- borderRadius: BorderRadius .circular (10 ),
119
128
),
120
129
),
121
- ),
122
- onLongPress:
123
- onLongPress != null ? () => onLongPress ! (entry.key) : null ,
124
- onPressed : () => onPressed (entry.key),
125
- child : Text (
126
- entry.value. text,
127
- style : BotStyle . text (context ),
130
+ onLongPress :
131
+ onLongPress != null ? () => onLongPress !(entry.key) : null ,
132
+ onPressed : () => onPressed (entry.key),
133
+ child : Text (
134
+ entry.value.text,
135
+ style : BotStyle . text (context) ,
136
+ ),
128
137
),
129
138
),
130
139
),
@@ -135,3 +144,110 @@ class ChoiceItem extends StatelessWidget {
135
144
}
136
145
}
137
146
}
147
+
148
+ class ChoiceAnimationWidget extends StatefulWidget {
149
+ final Widget child;
150
+ final bool selected;
151
+ final bool isGold;
152
+
153
+ const ChoiceAnimationWidget ({
154
+ super .key,
155
+ required this .child,
156
+ required this .selected,
157
+ this .isGold = false ,
158
+ });
159
+
160
+ @override
161
+ ChoiceAnimationWidgetState createState () => ChoiceAnimationWidgetState ();
162
+ }
163
+
164
+ class ChoiceAnimationWidgetState extends State <ChoiceAnimationWidget >
165
+ with SingleTickerProviderStateMixin {
166
+ late final AnimationController _controller;
167
+ late final Animation <double > _animation;
168
+ bool animationPlayed = false ;
169
+
170
+ @override
171
+ void initState () {
172
+ super .initState ();
173
+
174
+ _controller = AnimationController (
175
+ duration: const Duration (milliseconds: 300 ),
176
+ vsync: this ,
177
+ );
178
+
179
+ _animation = widget.isGold
180
+ ? Tween <double >(begin: 1.0 , end: 1.2 ).animate (_controller)
181
+ : TweenSequence <double >([
182
+ TweenSequenceItem <double >(
183
+ tween: Tween <double >(begin: 0 , end: - 8 * pi / 180 ),
184
+ weight: 1.0 ,
185
+ ),
186
+ TweenSequenceItem <double >(
187
+ tween: Tween <double >(begin: - 8 * pi / 180 , end: 16 * pi / 180 ),
188
+ weight: 2.0 ,
189
+ ),
190
+ TweenSequenceItem <double >(
191
+ tween: Tween <double >(begin: 16 * pi / 180 , end: 0 ),
192
+ weight: 1.0 ,
193
+ ),
194
+ ]).animate (_controller);
195
+
196
+ if (widget.selected && ! animationPlayed) {
197
+ _controller.forward ();
198
+ animationPlayed = true ;
199
+ setState (() {});
200
+ }
201
+ _controller.addStatusListener ((status) {
202
+ if (status == AnimationStatus .completed) {
203
+ _controller.reverse ();
204
+ } else if (status == AnimationStatus .dismissed) {
205
+ _controller.stop ();
206
+ _controller.reset ();
207
+ }
208
+ });
209
+ }
210
+
211
+ @override
212
+ void didUpdateWidget (ChoiceAnimationWidget oldWidget) {
213
+ super .didUpdateWidget (oldWidget);
214
+ if (widget.selected && ! animationPlayed) {
215
+ _controller.forward ();
216
+ animationPlayed = true ;
217
+ setState (() {});
218
+ }
219
+ }
220
+
221
+ @override
222
+ Widget build (BuildContext context) {
223
+ return widget.isGold
224
+ ? AnimatedBuilder (
225
+ key: UniqueKey (),
226
+ animation: _animation,
227
+ builder: (context, child) {
228
+ return Transform .scale (
229
+ scale: _animation.value,
230
+ child: child,
231
+ );
232
+ },
233
+ child: widget.child,
234
+ )
235
+ : AnimatedBuilder (
236
+ key: UniqueKey (),
237
+ animation: _animation,
238
+ builder: (context, child) {
239
+ return Transform .rotate (
240
+ angle: _animation.value,
241
+ child: child,
242
+ );
243
+ },
244
+ child: widget.child,
245
+ );
246
+ }
247
+
248
+ @override
249
+ void dispose () {
250
+ _controller.dispose ();
251
+ super .dispose ();
252
+ }
253
+ }
0 commit comments