import 'package:flutter/material.dart'; import 'package:gauge_indicator/gauge_indicator.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart'; class AqiGauge extends StatelessWidget { const AqiGauge({super.key, required this.aqi}); final double aqi; static const _minRange = 0.0; static const _goodRange = 50.0; static const _moderateRange = 100.0; static const _poorRange = 150.0; static const _unhealthyToSevereRange = 225.0; static const _maxRange = 300.0; Color _getPointerColor(double value) { if (value <= _goodRange) { return ColorsManager.goodGreen; } else if (value <= _moderateRange) { return ColorsManager.moderateYellow; } else if (value <= _poorRange) { return ColorsManager.poorOrange; } else { const unhealthyStart = _poorRange + 1; if (value <= _unhealthyToSevereRange) { final t = (value - unhealthyStart) / (_unhealthyToSevereRange - unhealthyStart); return Color.lerp( ColorsManager.unhealthyRed, ColorsManager.severePink, t, )!; } else { const severeStart = _unhealthyToSevereRange + 1; final t = (value - severeStart) / (_maxRange - severeStart); return Color.lerp( ColorsManager.severePink, ColorsManager.hazardousPurple, t, )!; } } } @override Widget build(BuildContext context) { return AnimatedRadialGauge( value: aqi, debug: false, duration: const Duration(milliseconds: 500), curve: Curves.easeInOut, initialValue: 0, alignment: Alignment.bottomCenter, builder: (context, child, value) { return Align( alignment: AlignmentDirectional.bottomCenter, child: FittedBox( fit: BoxFit.scaleDown, alignment: AlignmentDirectional.bottomCenter, child: Text.rich( TextSpan( text: value.toStringAsFixed(0), style: context.textTheme.bodySmall?.copyWith( color: ColorsManager.textPrimaryColor, fontWeight: FontWeight.w700, fontSize: 30, ), children: [ const TextSpan( text: 'AQI', style: TextStyle( color: ColorsManager.textPrimaryColor, fontWeight: FontWeight.w400, fontSize: 12, ), ), ], ), overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, ), ), ); }, axis: GaugeAxis( progressBar: const GaugeProgressBar.basic(color: Colors.transparent), style: const GaugeAxisStyle( cornerRadius: Radius.circular(16), thickness: 14, segmentSpacing: 4, ), min: _minRange, max: _maxRange, pointer: GaugePointer.circle( position: const GaugePointerPosition.surface(), radius: MediaQuery.sizeOf(context).width * 0.004, color: ColorsManager.whiteColors, border: GaugePointerBorder( width: 6, color: _getPointerColor(aqi), ), shadow: const BoxShadow( color: ColorsManager.blackColor, blurRadius: 6, offset: Offset(0, 2), ), ), transformer: const GaugeAxisTransformer.colorFadeIn( background: ColorsManager.transparentColor, interval: Interval(0, 0), ), segments: [ const GaugeSegment( from: _minRange, to: _goodRange, cornerRadius: Radius.circular(16), color: ColorsManager.goodGreen, ), const GaugeSegment( from: _goodRange + 1, to: _moderateRange, cornerRadius: Radius.circular(16), color: ColorsManager.moderateYellow, ), const GaugeSegment( from: _moderateRange + 1, to: _poorRange, cornerRadius: Radius.circular(16), color: ColorsManager.poorOrange, ), const GaugeSegment( from: _poorRange + 1, to: _maxRange, cornerRadius: Radius.circular(16), gradient: GaugeAxisGradient( colorStops: [0.0, 0.5, 1.0], colors: [ ColorsManager.unhealthyRed, ColorsManager.severePink, ColorsManager.hazardousPurple, ], ), ), ], ), ); } }