import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';

class CircularProgressBar extends StatefulWidget {
  final double percent;
  final double radius;
  final double width;
  final Widget center;

  CircularProgressBar({Key key, this.percent = 0.0, this.radius = 50.0, this.width = 10.0, this.center});

  @override
  State<StatefulWidget> createState() => _State();
}

class _State extends State<CircularProgressBar> with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin {
  AnimationController _animationController;
  Animation _animation;
  double _percent = 0.0;

  @override
  void dispose() {
    if (_animationController != null) {
      _animationController.dispose();
    }
    super.dispose();
  }

  @override
  void initState() {
    _animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 1000));
    _animation = Tween(begin: 0.0, end: widget.percent).animate(
      CurvedAnimation(parent: _animationController, curve: Curves.linear),
    )..addListener(() {
        setState(() {
          _percent = _animation.value;
        });
      });
    _animationController.addStatusListener((status) {});
    _animationController.forward();
    super.initState();
  }

  @override
  void didUpdateWidget(CircularProgressBar oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.percent != widget.percent) {
      if (_animationController != null) {
        _animationController.duration = Duration(milliseconds: 1000);
        _animation = Tween(begin: 0.0, end: widget.percent).animate(
          CurvedAnimation(parent: _animationController, curve: Curves.linear),
        );
        _animationController.forward(from: 0.0);
      } else {
        _updateProgress();
      }
    }
  }

  _updateProgress() {
    setState(() {
      _percent = widget.percent;
    });
  }

  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Container(
        height: widget.radius * 2 + widget.width,
        width: widget.radius * 2,
        child: AnimatedBuilder(
          animation: _animation,
          builder: (BuildContext context, Widget child) {
            return Padding(
              padding: const EdgeInsets.symmetric(vertical: 10.0),
              child: CustomPaint(
                painter: ProgressBarThree(_animation.value, width: widget.width, radius: widget.radius - widget.width / 2),
                child: (widget.center != null) ? Center(child: widget.center) : Container(),
              ),
            );
          },
        ));
  }
}

class ProgressBarThree extends CustomPainter {
  final double progress;
  final double width;
  final double radius;
  final Paint _bg = Paint()
    ..isAntiAlias = true
    ..color = const Color(0xfff1f1f1)
    ..style = PaintingStyle.stroke;
  final List<Paint> _p = [
    Paint()
      ..isAntiAlias = true
      ..color = const Color(0xffFFE600)
      ..style = PaintingStyle.stroke,
    Paint()
      ..isAntiAlias = true
      ..color = const Color(0xffFFAA00)
      ..style = PaintingStyle.stroke,
    Paint()
      ..isAntiAlias = true
      ..color = const Color(0xffFF7323)
      ..style = PaintingStyle.stroke
  ];

  ProgressBarThree(this.progress, {this.width = 10.0, this.radius = 50.0});

  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final rect = Rect.fromCircle(center: center, radius: this.radius);

    double max = math.pi * 2;
    double start = math.pi * 3 / 2;
    _bg.strokeWidth = width;

    int split = 3;
    double _angleEnd = max / split;
    double _endDiff = (_angleEnd - _angleEnd * 0.98) / 2;
    start += _endDiff;
    double _angle = start;

    for (var i = 0; i < split; i++) {
      canvas.drawArc(rect, _angle, _angleEnd* 0.98 , false, _bg);
      _angle += _angleEnd;
    }

    double _progress = 1.0 / split;
    start = math.pi * 3 / 2;
    start += _endDiff;
    _angle = start;
    double _progressTotal = math.min(this.progress, 1.0);
    for (var i = 0; i < split; i++) {
      double _percent = _progressTotal / _progress;
      _p[i].strokeWidth = width;
      canvas.drawArc(rect, _angle, _angleEnd * 0.98 * math.min(_percent, 1.0), false, _p[i]);
      _angle += _angleEnd;
      _progressTotal -= _progress;
      if (_progressTotal < 0) break;
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => this != oldDelegate;
}
