today attendance progress added(cont)
parent
efd9a6ed49
commit
b38f4287b6
@ -0,0 +1,144 @@
|
||||
import 'package:easy_localization/src/public_ext.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||
import 'package:mohem_flutter_app/widgets/circular_step_progress_bar.dart';
|
||||
|
||||
class TodayAttendanceScreen extends StatefulWidget {
|
||||
TodayAttendanceScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_TodayAttendanceScreenState createState() {
|
||||
return _TodayAttendanceScreenState();
|
||||
}
|
||||
}
|
||||
|
||||
class _TodayAttendanceScreenState extends State<TodayAttendanceScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: MyColors.backgroundBlackColor,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios, color: Colors.white),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
),
|
||||
backgroundColor: Colors.white,
|
||||
body: ListView(
|
||||
children: [
|
||||
Container(
|
||||
color: MyColors.backgroundBlackColor,
|
||||
padding: EdgeInsets.only(left: 21, right: 21, bottom: 21),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
"June 13, 2021".toText24(isBold: true, color: Colors.white),
|
||||
LocaleKeys.timeLeftToday.tr().toText16(color: Color(0xffACACAC)),
|
||||
21.height,
|
||||
Center(
|
||||
child: CircularStepProgressBar(
|
||||
totalSteps: 16 * 4,
|
||||
currentStep: 16,
|
||||
width: 216,
|
||||
height: 216,
|
||||
selectedColor: MyColors.gradiantEndColor,
|
||||
unselectedColor: MyColors.grey70Color,
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
"08:58:15".toText32(color: Colors.white, isBold: true),
|
||||
19.height,
|
||||
"Shift Time".tr().toText12(color: MyColors.greyACColor),
|
||||
"08:00 - 17:00".toText22(color: Colors.white, isBold: true),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
color: MyColors.backgroundBlackColor,
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
height: 187,
|
||||
padding: EdgeInsets.only(left: 31, right: 31, top: 31, bottom: 16),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)),
|
||||
gradient: const LinearGradient(transform: GradientRotation(.64), begin: Alignment.topRight, end: Alignment.bottomRight, colors: [
|
||||
MyColors.gradiantEndColor,
|
||||
MyColors.gradiantStartColor,
|
||||
]),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [commonStatusView("Check In", "09:27"), commonStatusView("Check Out", "- - : - -")],
|
||||
),
|
||||
21.height,
|
||||
Row(
|
||||
children: [commonStatusView("Late In", "00:27"), commonStatusView("Regular", "08:00")],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white),
|
||||
margin: EdgeInsets.only(top: 187 - 31),
|
||||
padding: EdgeInsets.only(left: 21, right: 21, top: 24, bottom: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: ["Mark".tr().toText12(), "Attendance".tr().toText24(), "Select the method to mark the attendance".tr().toText12(color: Color(0xff535353)), 24.height],
|
||||
),
|
||||
),
|
||||
// Positioned(
|
||||
// top: 187 - 21,
|
||||
// child: Container(
|
||||
// padding: EdgeInsets.only(left: 31, right: 31, top: 31, bottom: 16),
|
||||
// decoration: BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white),
|
||||
// child: Column(
|
||||
// children: [
|
||||
// Row(
|
||||
// children: [commonStatusView("Check In", "09:27"), commonStatusView("Check Out", "- - : - -")],
|
||||
// ),
|
||||
// 21.height,
|
||||
// Row(
|
||||
// children: [commonStatusView("Late In", "00:27"), commonStatusView("Regular", "08:00")],
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget commonStatusView(String title, String time) => Expanded(
|
||||
child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
title.toText12(color: Colors.white),
|
||||
time.toText22(color: Colors.white, isBold: true),
|
||||
]),
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,515 @@
|
||||
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!");
|
||||
final 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
|
||||
final 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) {
|
||||
final w = size.width;
|
||||
final h = size.height;
|
||||
|
||||
// Step length is user-defined arcSize
|
||||
// divided by the total number of steps (each step same size)
|
||||
final stepLength = arcSize / totalSteps;
|
||||
|
||||
// Define general arc paint
|
||||
Paint paint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = maxDefinedSize;
|
||||
|
||||
final 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
|
||||
final 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
|
||||
final isSelectedColor = _isSelectedColor(step, isClockwise);
|
||||
|
||||
// Size of the step
|
||||
final indexStepSize = customStepSize != null
|
||||
// Consider step index inverted when counterclockwise
|
||||
? customStepSize!(_indexOfStep(step, isClockwise), isSelectedColor)
|
||||
: isSelectedColor
|
||||
? selectedStepSize ?? stepSize
|
||||
: unselectedStepSize ?? stepSize;
|
||||
|
||||
// Use customColor if defined
|
||||
final stepColor = customColor != null
|
||||
// Consider step index inverted when counterclockwise
|
||||
? customColor!(_indexOfStep(step, isClockwise))
|
||||
: isSelectedColor
|
||||
? selectedColor!
|
||||
: unselectedColor!;
|
||||
|
||||
// Apply stroke cap to each step
|
||||
final hasStrokeCap = roundedCap != null ? roundedCap!(_indexOfStep(step, isClockwise), isSelectedColor) : false;
|
||||
final 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
|
||||
final extraCapSize = indexStepSize / 2;
|
||||
final extraCapAngle = extraCapSize / (rect.width / 2);
|
||||
final 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
|
||||
final firstStepColor = isClockwise ? selectedColor : unselectedColor;
|
||||
final secondStepColor = !isClockwise ? selectedColor : unselectedColor;
|
||||
|
||||
// Selected and unselected step sizes if defined, otherwise use stepSize
|
||||
final firstStepSize = isClockwise ? selectedStepSize ?? stepSize : unselectedStepSize ?? stepSize;
|
||||
final secondStepSize = !isClockwise ? selectedStepSize ?? stepSize : unselectedStepSize ?? stepSize;
|
||||
|
||||
// Compute length and starting angle of the selected and unselected bars
|
||||
final firstArcLength = arcSize * (currentStep / totalSteps);
|
||||
final secondArcLength = arcSize - firstArcLength;
|
||||
|
||||
// firstArcStartingAngle = startingAngle
|
||||
final 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
|
||||
final firstArcStrokeCap = roundedCap != null
|
||||
? isClockwise
|
||||
? roundedCap!(0, true)
|
||||
: roundedCap!(1, false)
|
||||
: false;
|
||||
final secondArcStrokeCap = roundedCap != null
|
||||
? isClockwise
|
||||
? roundedCap!(1, false)
|
||||
: roundedCap!(0, true)
|
||||
: false;
|
||||
final firstCap = firstArcStrokeCap ? StrokeCap.round : StrokeCap.butt;
|
||||
final 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
|
||||
get semanticsBuilder => null;
|
||||
|
||||
@override
|
||||
bool shouldRebuildSemantics(CustomPainter oldDelegate) => false;
|
||||
}
|
||||
|
||||
/// Used to define the [circularDirection] attribute of the [CircularStepProgressBar]
|
||||
enum CircularDirection {
|
||||
clockwise,
|
||||
counterclockwise,
|
||||
}
|
||||
Loading…
Reference in New Issue