Aidra Connect 10.0.2+16
Aidra Connect Mobile Application
Loading...
Searching...
No Matches
segmented_circular_progress.dart
Go to the documentation of this file.
1import 'dart:math';
2import 'package:connect/core/localization/app_localizations.dart';
3
4import '/core/ui/widgets/custom_card.dart';
5import 'package:flutter/material.dart';
6import 'package:flutter_screenutil/flutter_screenutil.dart';
7import 'dart:math';
8
9class Co2EmissionIndicator extends StatelessWidget {
10 final double value;
11
12 const Co2EmissionIndicator({
13 Key? key,
14 required this.value,
15 }) : super(key: key);
16
17 @override
18 Widget build(BuildContext context) {
19 return SizedBox(
20 width: MediaQuery.of(context).size.width,
22 padding: EdgeInsets.all(30.sp),
23 child: CO2GaugeChart(
24 value: 16246,
25 maxValue: 30000,
26 label: AppLocalizations.of(context).translate('CO₂ Emission'),
27 size: 200.sp,
28 ),
29 ),
30 );
31 }
32}
33
34class Co2ArcIndicator extends StatelessWidget {
35 const Co2ArcIndicator({
36 Key? key,
37 }) : super(key: key);
38
39 @override
40 Widget build(BuildContext context) {
41 return SizedBox(
42 width: 200.sp,
43 height: 70.sp,
44 child: const CustomPaint(
45 painter: ArcPainter(),
46 ),
47 );
48 }
49}
50
51class ArcPainter extends CustomPainter {
52 const ArcPainter();
53
54 @override
55 void paint(Canvas canvas, Size size) {
56 final center = Offset(size.width / 2, size.height - 20);
57 final radius = size.width * 0.45;
58 const startAngle = -5 * pi / 4; // -225 degrees
59 const endAngle = pi / 4; // 45 degrees
60 const strokeWidth = 6.0;
61
62 // Define segments with small gaps
63 const segments = [
64 SegmentData(Color(0xFFFF6B3D), 0.145),
65 SegmentData(Color(0xFF4CAF50), 0.34),
66 SegmentData(Color(0xFFFF4B4B), 0.34),
67 SegmentData(Color(0xFF2196F3), 0.145),
68 ];
69
70 // Draw segments
71 double currentAngle = startAngle;
72 final totalAngle = endAngle - startAngle;
73 const gapAngle = pi / 90; // Small gap between segments
74
75 for (final segment in segments) {
76 final paint = Paint()
77 ..color = segment.color
78 ..style = PaintingStyle.stroke
80 ..strokeCap = StrokeCap.round;
81
82 final sweepAngle = (totalAngle * segment.percentage) - gapAngle;
83
84 canvas.drawArc(
85 Rect.fromCircle(center: center, radius: radius),
86 currentAngle,
87 sweepAngle,
88 false,
89 paint,
90 );
91
92 // Draw end dot
93 final dotPaint = Paint()
94 ..color = segment.color
95 ..style = PaintingStyle.fill;
96
97 final angleForDot = currentAngle + sweepAngle;
98 final dotCenter = Offset(
99 center.dx + radius * cos(angleForDot),
100 center.dy + radius * sin(angleForDot),
101 );
102
103 canvas.drawCircle(dotCenter, strokeWidth / 1.8, dotPaint);
104
105 currentAngle += sweepAngle + gapAngle;
106 }
107
108 // Draw the extra blue dot at the end
109 if (segments.isNotEmpty) {
110 final lastSegment = segments.last;
111 final extraDotCenter = Offset(
112 center.dx + radius * cos(endAngle),
113 center.dy + radius * sin(endAngle) - 8, // Offset slightly up
114 );
115
116 canvas.drawCircle(
117 extraDotCenter,
118 strokeWidth / 1.8,
119 Paint()..color = lastSegment.color,
120 );
121 }
122 }
123
124 @override
125 bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
126}
127
128class SegmentData {
129 final Color color;
130 final double percentage;
131
132 const SegmentData(this.color, this.percentage);
133}
134
135class CO2GaugeChart extends StatelessWidget {
136 final double value; // Current value
137 final double maxValue; // Maximum possible value
138 final String label; // Label text
139 final double size; // Size of the gauge
140
141 const CO2GaugeChart({
142 Key? key,
143 required this.value,
144 required this.maxValue,
145 required this.label,
146 this.size = 200,
147 }) : super(key: key);
148
149 @override
150 Widget build(BuildContext context) {
151 return SizedBox(
152 width: size,
153 child: Stack(
154 children: [
155 Center(
156 child: CustomPaint(
157 size: Size(size, size / 2),
158 painter: GaugePainter(
159 value: value,
161 ),
162 ),
163 ),
164 Positioned(
165 left: 0,
166 right: 0,
167 bottom: 0,
168 top: 40.sp,
169 child: Column(
170 children: [
171 Text(
172 label,
173 style: const TextStyle(
174 color: Colors.grey,
175 fontSize: 14,
176 ),
177 ),
178 SizedBox(height: 5.sp),
179 Text(
180 '${value.toStringAsFixed(0)} kg',
181 style: const TextStyle(
182 fontSize: 24,
183 fontWeight: FontWeight.bold,
184 ),
185 ),
186 ],
187 ),
188 ),
189 ],
190 ),
191 );
192 }
193}
194
195class GaugePainter extends CustomPainter {
196 final double value;
197 final double maxValue;
198
200 required this.value,
201 required this.maxValue,
202 });
203
204 @override
205 void paint(Canvas canvas, Size size) {
206 final center = Offset(size.width / 2, size.height);
207 final radius = size.height;
208 const startAngle = pi;
209 const sweepAngle = pi;
210
211 // Define colors for segments
212 final colors = [
213 Colors.orange,
214 Colors.green,
215 Colors.red,
216 Colors.blue,
217 ];
218
219 // Background arc (gray)
220 final bgPaint = Paint()
221 ..color = Colors.grey[200]!
222 ..style = PaintingStyle.stroke
223 ..strokeWidth = 12;
224
225 canvas.drawArc(
226 Rect.fromCircle(center: center, radius: radius),
227 startAngle,
228 sweepAngle,
229 false,
230 bgPaint,
231 );
232
233 // Calculate segment positions
234 final segmentAngle = sweepAngle / colors.length;
235 final progress = (value / maxValue).clamp(0.0, 1.0);
236 final progressAngle = sweepAngle * progress;
237
238 // Draw colored segments
239 var currentAngle = startAngle;
240 for (var i = 0; i < colors.length; i++) {
241 final paint = Paint()
242 ..color = colors[i]
243 ..style = PaintingStyle.stroke
244 ..strokeWidth = 12
245 ..strokeCap = StrokeCap.round;
246
247 final segEnd = currentAngle + segmentAngle;
248 final drawAngle = progressAngle - (startAngle - currentAngle);
249
250 if (drawAngle > 0) {
251 canvas.drawArc(
252 Rect.fromCircle(center: center, radius: radius),
253 currentAngle,
254 min(segmentAngle, drawAngle),
255 false,
256 paint,
257 );
258 }
259
260 // Draw dots at segment boundaries
261 final dotPaint = Paint()
262 ..color = colors[i]
263 ..style = PaintingStyle.fill;
264
265 final dotPosition = Offset(
266 center.dx + radius * cos(currentAngle),
267 center.dy + radius * sin(currentAngle),
268 );
269
270 canvas.drawCircle(dotPosition, 6, dotPaint);
271
272 currentAngle = segEnd;
273 }
274 }
275
276 @override
277 bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
278}
String translate(String key)
static AppLocalizations of(BuildContext context)
const ArcPainter()
override void paint(Canvas canvas, Size size)
override bool shouldRepaint(CustomPainter oldDelegate)
final double strokeWidth
override bool shouldRepaint(covariant CustomPainter oldDelegate)
const Co2EmissionIndicator({ Key? key, required this.value, }) override Widget build(BuildContext context)
const CustomCard({ super.key, required this.child, this.padding, this.bgColor, })
final Widget child
override Widget build(BuildContext context)
Definition app_view.dart:19
const CO2GaugeChart({ Key? key, required this.value, required this.maxValue, required this.label, this.size=200, }) override Widget build(BuildContext context)
final String label
final Widget child
final double percentage
final Color color
Definition failures.dart:1
const SegmentData(this.color, this.percentage)
override void paint(Canvas canvas, Size size)
final double value
final double maxValue
GaugePainter({ required this.value, required this.maxValue, })
class ArcPainter extends CustomPainter color
final double progress