library easy_stepper; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'components/base_step.dart'; import 'components/custom_line.dart'; class CustomStepper extends StatefulWidget { final List steps; final OnStepReached ?onStepReached; final Color ?unreachedStepBackgroundColor; final Color ?unreachedStepTextColor; final Color ?unreachedStepIconColor; final Color ?unreachedStepBorderColor; final BorderType ?unreachedStepBorderType; final Color activeStepBackgroundColor; final Color? activeStepTextColor; final Color activeStepIconColor; final Color activeStepBorderColor; final BorderType ?activeStepBorderType; final Color finishedStepBackgroundColor; final Color ?finishedStepBorderColor; final Color ?finishedStepTextColor; final Color ?finishedStepIconColor; final BorderType ?finishedStepBorderType; final double stepRadius; final int activeStep; final int ?maxReachedStep; final Set? reachedSteps; final AlignmentGeometry alignment; final double internalPadding; final EdgeInsetsGeometry padding; final bool titlesAreLargerThanSteps; final Curve stepAnimationCurve; final Duration stepAnimationDuration; final double borderThickness; final StepShape stepShape; final double ?stepBorderRadius; final bool showStepBorder; final bool showScrollbar; final bool fitWidth; final LineStyle ?lineStyle; const CustomStepper({ Key? key, required this.activeStep, required this.steps, this.reachedSteps, this.maxReachedStep, this.onStepReached, this.unreachedStepBackgroundColor, this.unreachedStepTextColor, this.unreachedStepIconColor, this.unreachedStepBorderColor, this.activeStepTextColor, this.activeStepIconColor=AppColor.primary10, this.activeStepBackgroundColor=AppColor.primary10, this.activeStepBorderColor=AppColor.primary10, this.finishedStepBackgroundColor=AppColor.primary10, this.finishedStepBorderColor, this.finishedStepIconColor, this.stepRadius = 20, this.alignment = Alignment.center, this.fitWidth = true, this.showScrollbar = false, this.padding=EdgeInsetsDirectional.zero, this.titlesAreLargerThanSteps = false, this.internalPadding = 8, this.stepAnimationCurve = Curves.linear, this.stepAnimationDuration = const Duration(seconds: 1), this.borderThickness = 1, this.stepShape = StepShape.circle, this.stepBorderRadius, this.unreachedStepBorderType, this.activeStepBorderType, this.finishedStepBorderType, this.showStepBorder = false, this.lineStyle, this.finishedStepTextColor, }) : assert(maxReachedStep == null || reachedSteps == null, 'only "maxReachedStep" or "reachedSteps" allowed'), super(key: key); @override State createState() => _CustomStepperState(); } class _CustomStepperState extends State { late ScrollController _scrollController; int ?_selectedIndex; LineStyle? lineStyle; EdgeInsetsGeometry? _padding; @override void initState() { lineStyle = widget.lineStyle ?? const LineStyle(); _selectedIndex = widget.activeStep; _scrollController = ScrollController(); _padding = const EdgeInsetsDirectional.all(10); if (widget.steps.any((element) => element.topTitle??false)) { _padding = _padding!.add(const EdgeInsetsDirectional.only(top: 45)); } if (widget.titlesAreLargerThanSteps) { _padding = _padding!.add(EdgeInsetsDirectional.symmetric( horizontal: lineStyle!.lineLength / 2)); } _padding!.add(widget.padding); super.initState(); } @override void didUpdateWidget(CustomStepper oldWidget) { super.didUpdateWidget(oldWidget); // Verify that the active step falls within a valid range. if (widget.activeStep >= 0 && widget.activeStep < widget.steps.length) { _selectedIndex = widget.activeStep; } } @override void dispose() { _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { lineStyle = widget.lineStyle ?? const LineStyle(); return Align( alignment: widget.alignment, child: NotificationListener( onNotification: (OverscrollIndicatorNotification overscroll) { overscroll.disallowIndicator(); return false; }, child: FittedBox( fit: widget.fitWidth ? BoxFit.fitWidth : BoxFit.none, child: Row( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: _buildEasySteps(), ), ) ), ); } List _buildEasySteps() { return List.generate(widget.steps.length, (index) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildStep(index), _buildLine(index, Axis.horizontal), ], ); }); } BaseStep _buildStep(int index) { final step = widget.steps[index]; return BaseStep( step: step, radius: widget.stepRadius, isActive: index == widget.activeStep, isFinished: widget.reachedSteps != null ? index < widget.activeStep && widget.reachedSteps!.contains(index) : index < widget.activeStep, isUnreached: index > widget.activeStep, isAlreadyReached: widget.reachedSteps != null ? widget.reachedSteps!.contains(index) : widget.maxReachedStep != null ? index <= widget.maxReachedStep! : false, activeStepBackgroundColor: widget.activeStepBackgroundColor, activeStepBorderColor: widget.activeStepBorderColor, activeTextColor: widget.activeStepTextColor??AppColor.neutral100, activeIconColor: widget.activeStepIconColor, unreachedBackgroundColor: widget.unreachedStepBackgroundColor??AppColor.white10, unreachedBorderColor: widget.unreachedStepBorderColor??AppColor.neutral100, unreachedTextColor: widget.unreachedStepTextColor??AppColor.neutral100, unreachedIconColor: widget.unreachedStepIconColor??AppColor.neutral100, padding: max(widget.internalPadding, 0), stepRadius: widget.stepBorderRadius??10, showStepBorder: widget.showStepBorder, lineLength: lineStyle!.lineLength, enabled: widget.steps[index].enabled??false, ); } // BorderType _handleBorderType(int index) { // if (index == widget.activeStep) { // //Active Step // return widget.activeStepBorderType ?? widget.defaultStepBorderType; // } else if (index > widget.activeStep) { // //Unreached Step // return widget.unreachedStepBorderType ?? widget.defaultStepBorderType; // } else if (index < widget.activeStep) { // //Finished Step // return widget.finishedStepBorderType ?? widget.defaultStepBorderType; // } else { // return widget.defaultStepBorderType; // } // } Color _getLineColor(int index) { Color ?preferredColor; if (index == widget.activeStep) { //Active Step preferredColor = lineStyle!.activeLineColor??AppColor.primary10; } else if (index > widget.activeStep) { //Unreached Step preferredColor = lineStyle!.unreachedLineColor??AppColor.primary10; } else if (index < widget.activeStep) { //Finished Step preferredColor = lineStyle!.finishedLineColor??AppColor.primary10; } return preferredColor ?? lineStyle!.defaultLineColor ?? Theme.of(context).colorScheme.primary; } Widget _buildLine(int index, Axis axis) { return index < widget.steps.length - 1 ? Column( children: [ Padding( padding: EdgeInsets.only( top: axis == Axis.horizontal ? (widget.stepRadius - lineStyle!.lineThickness) : 0, ), child: _buildBaseLine(index, axis), ), if (axis == Axis.horizontal) ...[ const SizedBox(height: 5), SizedBox( width: lineStyle!.lineLength, child: widget.steps[index].customLineWidget ?? Text( widget.steps[index].lineText??'', maxLines: 3, textAlign: TextAlign.center, style: Theme.of(context).textTheme.labelSmall, ), ), ], ], ) : const Offstage(); } EasyLine _buildBaseLine(int index, Axis axis) { return EasyLine( length: lineStyle!.lineLength, color: _getLineColor(index), thickness: lineStyle!.lineThickness, spacing: lineStyle!.lineSpace, width: lineStyle!.lineWidth, axis: axis, lineType: index > widget.activeStep - 1 && lineStyle!.unreachedLineType != null ? lineStyle!.unreachedLineType : lineStyle!.lineType, ); } }