You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			516 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Dart
		
	
			
		
		
	
	
			516 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Dart
		
	
import 'dart:math' as math;
 | 
						|
 | 
						|
import 'package:flutter/material.dart';
 | 
						|
 | 
						|
class CircularStepProgressBar extends StatelessWidget {
 | 
						|
  /// Defines if steps grow from
 | 
						|
  /// clockwise [CircularDirection.clockwise] or
 | 
						|
  /// counterclockwise [CircularDirection.counterclockwise]
 | 
						|
  final CircularDirection circularDirection;
 | 
						|
 | 
						|
  /// Number of steps to underline, all the steps with
 | 
						|
  /// index <= [currentStep] will have [Color] equal to
 | 
						|
  /// [selectedColor]
 | 
						|
  ///
 | 
						|
  /// Only used when [customColor] is [null]
 | 
						|
  ///
 | 
						|
  /// Default value: 0
 | 
						|
  final int currentStep;
 | 
						|
 | 
						|
  /// Total number of step of the complete indicator
 | 
						|
  final int totalSteps;
 | 
						|
 | 
						|
  /// Radial spacing between each step. Remember to
 | 
						|
  /// define the value in radiant units
 | 
						|
  ///
 | 
						|
  /// Default value: math.pi / 20
 | 
						|
  final double padding;
 | 
						|
 | 
						|
  /// Height of the indicator's box container
 | 
						|
  final double? height;
 | 
						|
 | 
						|
  /// Width of the indicator's box container
 | 
						|
  final double? width;
 | 
						|
 | 
						|
  /// Assign a custom [Color] for each step
 | 
						|
  ///
 | 
						|
  /// Takes a [int], index of the current step starting from 0, and
 | 
						|
  /// must return a [Color]
 | 
						|
  ///
 | 
						|
  /// **NOTE**: If provided, it overrides
 | 
						|
  /// [selectedColor] and [unselectedColor]
 | 
						|
  final Color Function(int)? customColor;
 | 
						|
 | 
						|
  /// [Color] of the selected steps
 | 
						|
  ///
 | 
						|
  /// All the steps with index <= [currentStep]
 | 
						|
  ///
 | 
						|
  /// Default value: [Colors.blue]
 | 
						|
  final Color? selectedColor;
 | 
						|
 | 
						|
  /// [Color] of the unselected steps
 | 
						|
  ///
 | 
						|
  /// All the steps with index between
 | 
						|
  /// [currentStep] and [totalSteps]
 | 
						|
  ///
 | 
						|
  /// Default value: [Colors.grey]
 | 
						|
  final Color? unselectedColor;
 | 
						|
 | 
						|
  /// The size of a single step in the indicator
 | 
						|
  ///
 | 
						|
  /// Default value: 6.0
 | 
						|
  final double stepSize;
 | 
						|
 | 
						|
  /// Specify a custom size for selected steps
 | 
						|
  ///
 | 
						|
  /// Only applicable when not custom setting (customColor, customStepSize) is defined
 | 
						|
  ///
 | 
						|
  /// This value will replace the [stepSize] only for selected steps
 | 
						|
  final double? selectedStepSize;
 | 
						|
 | 
						|
  /// Specify a custom size for unselected steps
 | 
						|
  ///
 | 
						|
  /// Only applicable when not custom setting (customColor, customStepSize) is defined
 | 
						|
  ///
 | 
						|
  /// This value will replace the [stepSize] only for unselected steps
 | 
						|
  final double? unselectedStepSize;
 | 
						|
 | 
						|
  /// Assign a custom size [double] for each step
 | 
						|
  ///
 | 
						|
  /// Function takes a [int], index of the current step starting from 0, and
 | 
						|
  /// a [bool], which tells if the step is selected based on [currentStep],
 | 
						|
  /// and must return a [double] size of the step
 | 
						|
  ///
 | 
						|
  /// **NOTE**: If provided, it overrides [stepSize]
 | 
						|
  final double Function(int, bool)? customStepSize;
 | 
						|
 | 
						|
  /// [Widget] contained inside the circular indicator
 | 
						|
  final Widget? child;
 | 
						|
 | 
						|
  /// Height of the indicator container in case no [height] parameter
 | 
						|
  /// given and parent height is [double.infinity]
 | 
						|
  ///
 | 
						|
  /// Default value: 100.0
 | 
						|
  final double fallbackHeight;
 | 
						|
 | 
						|
  /// Height of the indicator container in case no [width] parameter
 | 
						|
  /// given and parent height is [double.infinity]
 | 
						|
  ///
 | 
						|
  /// Default value: 100.0
 | 
						|
  final double fallbackWidth;
 | 
						|
 | 
						|
  /// Angle in radiants in which the first step of the indicator is placed.
 | 
						|
  /// The initial value is on the top of the indicator (- math.pi / 2)
 | 
						|
  /// - 0 => TOP
 | 
						|
  /// - math.pi / 2 => LEFT
 | 
						|
  /// - math.pi => BOTTOM
 | 
						|
  /// - math.pi / 2 * 3 => RIGHT
 | 
						|
  /// - math.pi / 2 => TOP (again)
 | 
						|
  final double startingAngle;
 | 
						|
 | 
						|
  /// Angle in radiants which represents the size of the arc used to display the indicator.
 | 
						|
  /// It allows you to draw a semi-circle instead of a full 360° (math.pi * 2) circle.
 | 
						|
  final double arcSize;
 | 
						|
 | 
						|
  /// Adds rounded edges at the beginning and at the end of the circular indicator
 | 
						|
  /// given a [int], index of each step, and a [bool],
 | 
						|
  /// which tells if the step is selected based on [currentStep], and must return a
 | 
						|
  /// [bool] that tells if the edges are rounded or not
 | 
						|
  ///
 | 
						|
  /// **NOTE**: For continuous circular indicators (`padding: 0`), to check if to apply
 | 
						|
  /// the rounded edges the packages uses index 0 (for the first arc painted) and
 | 
						|
  /// 1 (for the second arc painted)
 | 
						|
  ///
 | 
						|
  /// ```dart
 | 
						|
  /// // Example: Add rounded edges for all the steps
 | 
						|
  /// roundedCap: (index, _) => true
 | 
						|
  /// ```
 | 
						|
  ///
 | 
						|
  /// ```dart
 | 
						|
  /// // Example: Add rounded edges for the selected arc of the indicator
 | 
						|
  /// roundedCap: (index, _) => index == 0,
 | 
						|
  /// padding: 0
 | 
						|
  /// ```
 | 
						|
  final bool Function(int, bool)? roundedCap;
 | 
						|
 | 
						|
  /// Adds a gradient color to the circular indicator
 | 
						|
  ///
 | 
						|
  /// **NOTE**: If provided, it overrides [selectedColor], [unselectedColor], and [customColor]
 | 
						|
  final Gradient? gradientColor;
 | 
						|
 | 
						|
  /// Removes the extra angle caused by [StrokeCap.round] when [roundedCap] is applied
 | 
						|
  final bool removeRoundedCapExtraAngle;
 | 
						|
 | 
						|
  const CircularStepProgressBar({
 | 
						|
    required this.totalSteps,
 | 
						|
    this.child,
 | 
						|
    this.height,
 | 
						|
    this.width,
 | 
						|
    this.customColor,
 | 
						|
    this.customStepSize,
 | 
						|
    this.selectedStepSize,
 | 
						|
    this.unselectedStepSize,
 | 
						|
    this.roundedCap,
 | 
						|
    this.gradientColor,
 | 
						|
    this.circularDirection = CircularDirection.clockwise,
 | 
						|
    this.fallbackHeight = 100.0,
 | 
						|
    this.fallbackWidth = 100.0,
 | 
						|
    this.currentStep = 0,
 | 
						|
    this.selectedColor = Colors.blue,
 | 
						|
    this.unselectedColor = Colors.grey,
 | 
						|
    this.padding = math.pi / 20,
 | 
						|
    this.stepSize = 6.0,
 | 
						|
    this.startingAngle = 0,
 | 
						|
    this.arcSize = math.pi * 2,
 | 
						|
    this.removeRoundedCapExtraAngle = false,
 | 
						|
    Key? key,
 | 
						|
  })  : assert(totalSteps > 0, "Number of total steps (totalSteps) of the CircularStepProgressBar must be greater than 0"),
 | 
						|
        assert(currentStep >= 0, "Current step (currentStep) of the CircularStepProgressBar must be greater than or equal to 0"),
 | 
						|
        assert(padding >= 0.0, "Padding (padding) of the CircularStepProgressBar must be greater or equal to 0"),
 | 
						|
        super(key: key);
 | 
						|
 | 
						|
  @override
 | 
						|
  Widget build(BuildContext context) {
 | 
						|
    // Print warning when arcSize greater than math.pi * 2 which causes steps to overlap
 | 
						|
    if (arcSize > math.pi * 2) print("WARNING (step_progress_indicator): arcSize of CircularStepProgressBar is greater than 360° (math.pi * 2), this will cause some steps to overlap!");
 | 
						|
    TextDirection textDirection = Directionality.of(context);
 | 
						|
 | 
						|
    return LayoutBuilder(
 | 
						|
      builder: (context, constraints) => SizedBox(
 | 
						|
        // Apply fallback for both height and width
 | 
						|
        // if their value is null and no parent size limit
 | 
						|
        height: height != null
 | 
						|
            ? height
 | 
						|
            : constraints.maxHeight != double.infinity
 | 
						|
                ? constraints.maxHeight
 | 
						|
                : fallbackHeight,
 | 
						|
        width: width != null
 | 
						|
            ? width
 | 
						|
            : constraints.maxWidth != double.infinity
 | 
						|
                ? constraints.maxWidth
 | 
						|
                : fallbackWidth,
 | 
						|
        child: CustomPaint(
 | 
						|
          painter: _CircularIndicatorPainter(
 | 
						|
            totalSteps: totalSteps,
 | 
						|
            currentStep: currentStep,
 | 
						|
            customColor: customColor,
 | 
						|
            padding: padding,
 | 
						|
            circularDirection: circularDirection,
 | 
						|
            selectedColor: selectedColor,
 | 
						|
            unselectedColor: unselectedColor,
 | 
						|
            arcSize: arcSize,
 | 
						|
            stepSize: stepSize,
 | 
						|
            customStepSize: customStepSize,
 | 
						|
            maxDefinedSize: maxDefinedSize,
 | 
						|
            selectedStepSize: selectedStepSize,
 | 
						|
            unselectedStepSize: unselectedStepSize,
 | 
						|
            startingAngle: startingAngleTopOfIndicator,
 | 
						|
            roundedCap: roundedCap,
 | 
						|
            gradientColor: gradientColor,
 | 
						|
            textDirection: textDirection,
 | 
						|
            removeRoundedCapExtraAngle: removeRoundedCapExtraAngle,
 | 
						|
          ),
 | 
						|
          // Padding needed to show the indicator when child is placed on top of it
 | 
						|
          child: Padding(
 | 
						|
            padding: EdgeInsets.all(maxDefinedSize),
 | 
						|
            child: child,
 | 
						|
          ),
 | 
						|
        ),
 | 
						|
      ),
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  /// Compute the maximum possible size of the indicator between
 | 
						|
  /// [stepSize] and [customStepSize]
 | 
						|
  double get maxDefinedSize {
 | 
						|
    if (customStepSize == null) {
 | 
						|
      return math.max(stepSize, math.max(selectedStepSize ?? 0, unselectedStepSize ?? 0));
 | 
						|
    }
 | 
						|
 | 
						|
    // When customSize defined, compute and return max possible size
 | 
						|
    double currentMaxSize = 0;
 | 
						|
 | 
						|
    for (int step = 0; step < totalSteps; ++step) {
 | 
						|
      // Consider max between selected and unselected case
 | 
						|
      var customSizeValue = math.max(customStepSize!(step, false), customStepSize!(step, true));
 | 
						|
      if (customSizeValue > currentMaxSize) {
 | 
						|
        currentMaxSize = customSizeValue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return currentMaxSize;
 | 
						|
  }
 | 
						|
 | 
						|
  /// Make [startingAngle] to top-center of indicator (0°) by default
 | 
						|
  double get startingAngleTopOfIndicator => startingAngle - math.pi / 2;
 | 
						|
}
 | 
						|
 | 
						|
class _CircularIndicatorPainter implements CustomPainter {
 | 
						|
  final int totalSteps;
 | 
						|
  final int currentStep;
 | 
						|
  final double padding;
 | 
						|
  final Color? selectedColor;
 | 
						|
  final Color? unselectedColor;
 | 
						|
  final double stepSize;
 | 
						|
  final double? selectedStepSize;
 | 
						|
  final double? unselectedStepSize;
 | 
						|
  final double Function(int, bool)? customStepSize;
 | 
						|
  final double maxDefinedSize;
 | 
						|
  final Color Function(int)? customColor;
 | 
						|
  final CircularDirection circularDirection;
 | 
						|
  final double startingAngle;
 | 
						|
  final double arcSize;
 | 
						|
  final bool Function(int, bool)? roundedCap;
 | 
						|
  final Gradient? gradientColor;
 | 
						|
  final TextDirection textDirection;
 | 
						|
  final bool removeRoundedCapExtraAngle;
 | 
						|
 | 
						|
  _CircularIndicatorPainter({
 | 
						|
    required this.totalSteps,
 | 
						|
    required this.circularDirection,
 | 
						|
    required this.customColor,
 | 
						|
    required this.currentStep,
 | 
						|
    required this.selectedColor,
 | 
						|
    required this.unselectedColor,
 | 
						|
    required this.padding,
 | 
						|
    required this.stepSize,
 | 
						|
    required this.selectedStepSize,
 | 
						|
    required this.unselectedStepSize,
 | 
						|
    required this.customStepSize,
 | 
						|
    required this.startingAngle,
 | 
						|
    required this.arcSize,
 | 
						|
    required this.maxDefinedSize,
 | 
						|
    required this.roundedCap,
 | 
						|
    required this.gradientColor,
 | 
						|
    required this.textDirection,
 | 
						|
    required this.removeRoundedCapExtraAngle,
 | 
						|
  });
 | 
						|
 | 
						|
  @override
 | 
						|
  void paint(Canvas canvas, Size size) {
 | 
						|
    var w = size.width;
 | 
						|
    var h = size.height;
 | 
						|
 | 
						|
    // Step length is user-defined arcSize
 | 
						|
    // divided by the total number of steps (each step same size)
 | 
						|
    var stepLength = arcSize / totalSteps;
 | 
						|
 | 
						|
    // Define general arc paint
 | 
						|
    Paint paint = Paint()
 | 
						|
      ..style = PaintingStyle.stroke
 | 
						|
      ..strokeWidth = maxDefinedSize;
 | 
						|
 | 
						|
    var rect = Rect.fromCenter(
 | 
						|
      // Rect created from the center of the widget
 | 
						|
      center: Offset(w / 2, h / 2),
 | 
						|
      // For both height and width, subtract maxDefinedSize to fit indicator inside the parent container
 | 
						|
      height: h - maxDefinedSize,
 | 
						|
      width: w - maxDefinedSize,
 | 
						|
    );
 | 
						|
 | 
						|
    if (gradientColor != null) {
 | 
						|
      paint.shader = gradientColor!.createShader(rect, textDirection: textDirection);
 | 
						|
    }
 | 
						|
 | 
						|
    // Change color selected or unselected based on the circularDirection
 | 
						|
    var isClockwise = circularDirection == CircularDirection.clockwise;
 | 
						|
 | 
						|
    // Make a continuous arc without rendering all the steps when possible
 | 
						|
    if (padding == 0 && customColor == null && customStepSize == null && roundedCap == null) {
 | 
						|
      _drawContinuousArc(canvas, paint, rect, isClockwise);
 | 
						|
    } else {
 | 
						|
      _drawStepArc(canvas, paint, rect, isClockwise, stepLength);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /// Draw a series of arcs, each composing the full steps of the indicator
 | 
						|
  void _drawStepArc(Canvas canvas, Paint paint, Rect rect, bool isClockwise, double stepLength) {
 | 
						|
    // Draw a series of circular arcs to compose the indicator
 | 
						|
    // Starting based on startingAngle attribute
 | 
						|
    //
 | 
						|
    // When clockwise:
 | 
						|
    // - Start drawing counterclockwise so to have the selected steps on top of the unselected
 | 
						|
    int step = isClockwise ? totalSteps - 1 : 0;
 | 
						|
    double stepAngle = isClockwise ? startingAngle - stepLength : startingAngle;
 | 
						|
    for (; isClockwise ? step >= 0 : step < totalSteps; isClockwise ? stepAngle -= stepLength : stepAngle += stepLength, isClockwise ? --step : ++step) {
 | 
						|
      // Check if the current step is selected or unselected
 | 
						|
      var isSelectedColor = _isSelectedColor(step, isClockwise);
 | 
						|
 | 
						|
      // Size of the step
 | 
						|
      var indexStepSize = customStepSize != null
 | 
						|
          // Consider step index inverted when counterclockwise
 | 
						|
          ? customStepSize!(_indexOfStep(step, isClockwise), isSelectedColor)
 | 
						|
          : isSelectedColor
 | 
						|
              ? selectedStepSize ?? stepSize
 | 
						|
              : unselectedStepSize ?? stepSize;
 | 
						|
 | 
						|
      // Use customColor if defined
 | 
						|
      var stepColor = customColor != null
 | 
						|
          // Consider step index inverted when counterclockwise
 | 
						|
          ? customColor!(_indexOfStep(step, isClockwise))
 | 
						|
          : isSelectedColor
 | 
						|
              ? selectedColor!
 | 
						|
              : unselectedColor!;
 | 
						|
 | 
						|
      // Apply stroke cap to each step
 | 
						|
      var hasStrokeCap = roundedCap != null ? roundedCap!(_indexOfStep(step, isClockwise), isSelectedColor) : false;
 | 
						|
      var strokeCap = hasStrokeCap ? StrokeCap.round : StrokeCap.butt;
 | 
						|
 | 
						|
      // Remove extra size caused by rounded stroke cap
 | 
						|
      // https://github.com/SandroMaglione/step-progress-indicator/issues/20#issue-786114745
 | 
						|
      var extraCapSize = indexStepSize / 2;
 | 
						|
      var extraCapAngle = extraCapSize / (rect.width / 2);
 | 
						|
      var extraCapRemove = hasStrokeCap && removeRoundedCapExtraAngle;
 | 
						|
 | 
						|
      // Draw arc steps of the indicator
 | 
						|
      _drawArcOnCanvas(
 | 
						|
        canvas: canvas,
 | 
						|
        rect: rect,
 | 
						|
        startingAngle: stepAngle + (extraCapRemove ? extraCapAngle : 0),
 | 
						|
        sweepAngle: stepLength - padding - (extraCapRemove ? extraCapAngle * 2 : 0),
 | 
						|
        paint: paint,
 | 
						|
        color: stepColor,
 | 
						|
        strokeWidth: indexStepSize,
 | 
						|
        strokeCap: strokeCap,
 | 
						|
      );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /// Draw optimized continuous indicator instead of multiple steps
 | 
						|
  void _drawContinuousArc(Canvas canvas, Paint paint, Rect rect, bool isClockwise) {
 | 
						|
    // Compute color of the selected and unselected bars
 | 
						|
    var firstStepColor = isClockwise ? selectedColor : unselectedColor;
 | 
						|
    var secondStepColor = !isClockwise ? selectedColor : unselectedColor;
 | 
						|
 | 
						|
    // Selected and unselected step sizes if defined, otherwise use stepSize
 | 
						|
    var firstStepSize = isClockwise ? selectedStepSize ?? stepSize : unselectedStepSize ?? stepSize;
 | 
						|
    var secondStepSize = !isClockwise ? selectedStepSize ?? stepSize : unselectedStepSize ?? stepSize;
 | 
						|
 | 
						|
    // Compute length and starting angle of the selected and unselected bars
 | 
						|
    var firstArcLength = arcSize * (currentStep / totalSteps);
 | 
						|
    var secondArcLength = arcSize - firstArcLength;
 | 
						|
 | 
						|
    // firstArcStartingAngle = startingAngle
 | 
						|
    var secondArcStartingAngle = startingAngle + firstArcLength;
 | 
						|
 | 
						|
    // Apply stroke cap to both arcs
 | 
						|
    // NOTE: For continuous circular indicator, it uses 0 and 1 as index to
 | 
						|
    // apply the rounded cap
 | 
						|
    var firstArcStrokeCap = roundedCap != null
 | 
						|
        ? isClockwise
 | 
						|
            ? roundedCap!(0, true)
 | 
						|
            : roundedCap!(1, false)
 | 
						|
        : false;
 | 
						|
    var secondArcStrokeCap = roundedCap != null
 | 
						|
        ? isClockwise
 | 
						|
            ? roundedCap!(1, false)
 | 
						|
            : roundedCap!(0, true)
 | 
						|
        : false;
 | 
						|
    var firstCap = firstArcStrokeCap ? StrokeCap.round : StrokeCap.butt;
 | 
						|
    var secondCap = secondArcStrokeCap ? StrokeCap.round : StrokeCap.butt;
 | 
						|
 | 
						|
    // When clockwise, draw the second arc first and the first on top of it
 | 
						|
    // Required when stroke cap is rounded to make the selected step on top of the unselected
 | 
						|
    if (circularDirection == CircularDirection.clockwise) {
 | 
						|
      // Second arc, selected when counterclockwise, unselected otherwise
 | 
						|
      _drawArcOnCanvas(
 | 
						|
        canvas: canvas,
 | 
						|
        rect: rect,
 | 
						|
        paint: paint,
 | 
						|
        startingAngle: secondArcStartingAngle,
 | 
						|
        sweepAngle: secondArcLength,
 | 
						|
        strokeWidth: secondStepSize,
 | 
						|
        color: secondStepColor!,
 | 
						|
        strokeCap: secondCap,
 | 
						|
      );
 | 
						|
 | 
						|
      // First arc, selected when clockwise, unselected otherwise
 | 
						|
      _drawArcOnCanvas(
 | 
						|
        canvas: canvas,
 | 
						|
        rect: rect,
 | 
						|
        paint: paint,
 | 
						|
        startingAngle: startingAngle,
 | 
						|
        sweepAngle: firstArcLength,
 | 
						|
        strokeWidth: firstStepSize,
 | 
						|
        color: firstStepColor!,
 | 
						|
        strokeCap: firstCap,
 | 
						|
      );
 | 
						|
    } else {
 | 
						|
      // First arc, selected when clockwise, unselected otherwise
 | 
						|
      _drawArcOnCanvas(
 | 
						|
        canvas: canvas,
 | 
						|
        rect: rect,
 | 
						|
        paint: paint,
 | 
						|
        startingAngle: startingAngle,
 | 
						|
        sweepAngle: firstArcLength,
 | 
						|
        strokeWidth: firstStepSize,
 | 
						|
        color: firstStepColor!,
 | 
						|
        strokeCap: firstCap,
 | 
						|
      );
 | 
						|
 | 
						|
      // Second arc, selected when counterclockwise, unselected otherwise
 | 
						|
      _drawArcOnCanvas(
 | 
						|
        canvas: canvas,
 | 
						|
        rect: rect,
 | 
						|
        paint: paint,
 | 
						|
        startingAngle: secondArcStartingAngle,
 | 
						|
        sweepAngle: secondArcLength,
 | 
						|
        strokeWidth: secondStepSize,
 | 
						|
        color: secondStepColor!,
 | 
						|
        strokeCap: secondCap,
 | 
						|
      );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /// Draw the actual arc for a continuous indicator
 | 
						|
  void _drawArcOnCanvas({
 | 
						|
    required Canvas canvas,
 | 
						|
    required Rect rect,
 | 
						|
    required double startingAngle,
 | 
						|
    required double sweepAngle,
 | 
						|
    required Paint paint,
 | 
						|
    required Color color,
 | 
						|
    required double strokeWidth,
 | 
						|
    required StrokeCap strokeCap,
 | 
						|
  }) =>
 | 
						|
      canvas.drawArc(
 | 
						|
        rect,
 | 
						|
        startingAngle,
 | 
						|
        sweepAngle,
 | 
						|
        false /*isRadial*/,
 | 
						|
        paint
 | 
						|
          ..color = color
 | 
						|
          ..strokeWidth = strokeWidth
 | 
						|
          ..strokeCap = strokeCap,
 | 
						|
      );
 | 
						|
 | 
						|
  bool _isSelectedColor(int step, bool isClockwise) => isClockwise ? step < currentStep : (step + 1) > (totalSteps - currentStep);
 | 
						|
 | 
						|
  /// Start counting indexes from the right if clockwise and on the left if counterclockwise
 | 
						|
  int _indexOfStep(int step, bool isClockwise) => isClockwise ? step : totalSteps - step - 1;
 | 
						|
 | 
						|
  @override
 | 
						|
  bool shouldRepaint(CustomPainter oldDelegate) => oldDelegate != this;
 | 
						|
 | 
						|
  @override
 | 
						|
  bool hitTest(Offset position) => false;
 | 
						|
 | 
						|
  @override
 | 
						|
  void addListener(listener) {}
 | 
						|
 | 
						|
  @override
 | 
						|
  void removeListener(listener) {}
 | 
						|
 | 
						|
  @override
 | 
						|
  Null get semanticsBuilder => null;
 | 
						|
 | 
						|
  @override
 | 
						|
  bool shouldRebuildSemantics(CustomPainter oldDelegate) => false;
 | 
						|
}
 | 
						|
 | 
						|
/// Used to define the [circularDirection] attribute of the [CircularStepProgressBar]
 | 
						|
enum CircularDirection {
 | 
						|
  clockwise,
 | 
						|
  counterclockwise,
 | 
						|
}
 |