22import 'package:flutter/material.dart' ;
33import 'package:percent_indicator/percent_indicator.dart' ;
44
5+ // UTILS
6+ import 'package:notredame/ui/utils/app_theme.dart' ;
7+
58// OTHERS
69import 'package:flutter_gen/gen_l10n/app_localizations.dart' ;
710
8- class GradeCircularProgress extends StatelessWidget {
11+ class GradeCircularProgress extends StatefulWidget {
912 final bool completed;
1013 final String finalGrade;
1114 final double studentGrade;
@@ -20,48 +23,120 @@ class GradeCircularProgress extends StatelessWidget {
2023 this .averageGrade})
2124 : super (key: key);
2225
26+ @override
27+ _GradeCircularProgressState createState () => _GradeCircularProgressState ();
28+ }
29+
30+ class _GradeCircularProgressState extends State <GradeCircularProgress >
31+ with TickerProviderStateMixin {
32+ AnimationController _controller;
33+ Animation <Color > animation;
34+
35+ @override
36+ void initState () {
37+ super .initState ();
38+
39+ _controller = AnimationController (
40+ duration: const Duration (milliseconds: 1100 ),
41+ vsync: this ,
42+ );
43+
44+ _controller.forward ();
45+
46+ animation = ColorTween (
47+ begin: AppTheme .gradeFailureMin,
48+ end: gradePercentageColor (widget.studentGrade ?? 0.0 ),
49+ ).animate (_controller)
50+ ..addListener (() {
51+ setState (() {});
52+ });
53+ }
54+
55+ @override
56+ void dispose () {
57+ _controller.dispose ();
58+ super .dispose ();
59+ }
60+
2361 @override
2462 Widget build (BuildContext context) {
2563 return CircularPercentIndicator (
2664 animation: true ,
2765 animationDuration: 1100 ,
28- radius: 100 * ratio,
29- lineWidth: 8.0 * ratio,
30- percent: completed ? getGradeInDecimals (studentGrade ?? 0.0 ) : 0 ,
66+ radius: 100 * widget.ratio,
67+ lineWidth: 8.0 * widget.ratio,
68+ percent:
69+ widget.completed ? getGradeInDecimals (widget.studentGrade ?? 0.0 ) : 0 ,
3170 circularStrokeCap: CircularStrokeCap .round,
3271 center: CircularPercentIndicator (
3372 animation: true ,
3473 animationDuration: 700 ,
35- radius: 80 * ratio,
36- lineWidth: 8.0 * ratio,
37- percent: completed ? getGradeInDecimals (averageGrade ?? 0.0 ) : 0 ,
74+ radius: 80 * widget.ratio,
75+ lineWidth: 8.0 * widget.ratio,
76+ percent: widget.completed
77+ ? getGradeInDecimals (widget.averageGrade ?? 0.0 )
78+ : 0 ,
3879 circularStrokeCap: CircularStrokeCap .round,
3980 center: Text (
4081 getGrade (context),
4182 style: TextStyle (
4283 color: Theme .of (context).brightness == Brightness .light
4384 ? Colors .black
4485 : Colors .white,
45- fontSize: 22 * ratio),
86+ fontSize: 22 * widget. ratio),
4687 ),
4788 progressColor: Colors .red,
4889 ),
49- progressColor: Colors .green ,
90+ progressColor: animation.value ,
5091 );
5192 }
5293
5394 double getGradeInDecimals (double grade) => grade / 100 ;
5495
5596 String getGrade (BuildContext context) {
56- if (finalGrade != null ) {
57- return finalGrade;
97+ if (widget. finalGrade != null ) {
98+ return widget. finalGrade;
5899 }
59100
60- if (studentGrade != null ) {
101+ if (widget. studentGrade != null ) {
61102 return AppIntl .of (context)
62- .grades_grade_in_percentage (studentGrade.round ());
103+ .grades_grade_in_percentage (widget. studentGrade.round ());
63104 }
64105
65106 return AppIntl .of (context).grades_not_available;
66107 }
108+
109+ Color gradePercentageColor (double gradePercentage) {
110+ const double passingGrade = 50.0 ;
111+ const double minGoodGrade = 80.0 ;
112+ const double maxGrade = 100.0 ;
113+
114+ Color startColor;
115+ Color endColor;
116+ double colorProportion = gradePercentage;
117+
118+ if (gradePercentage >= 0 && gradePercentage <= passingGrade) {
119+ startColor = AppTheme .gradeFailureMin;
120+ endColor = AppTheme .gradeFailureMax;
121+ colorProportion /= passingGrade;
122+ } else if (gradePercentage > passingGrade &&
123+ gradePercentage <= minGoodGrade) {
124+ startColor = AppTheme .gradePassing;
125+ endColor = AppTheme .gradeGoodMin;
126+ colorProportion -= passingGrade;
127+ colorProportion /= minGoodGrade - passingGrade;
128+ } else {
129+ startColor = AppTheme .gradeGoodMin;
130+ endColor = AppTheme .gradeGoodMax;
131+
132+ if (colorProportion >= maxGrade) {
133+ colorProportion = 1 ;
134+ } else {
135+ colorProportion -= minGoodGrade;
136+ colorProportion /= maxGrade - minGoodGrade;
137+ }
138+ }
139+
140+ return Color .lerp (startColor, endColor, colorProportion);
141+ }
67142}
0 commit comments