Skip to content

Commit

Permalink
Add progress circle
Browse files Browse the repository at this point in the history
  • Loading branch information
Osman authored and Osman committed Feb 22, 2024
1 parent 9f0e7f2 commit 675ab6d
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 4 deletions.
17 changes: 13 additions & 4 deletions example/lib/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:zeta_example/pages/components/checkbox_example.dart';
import 'package:zeta_example/pages/components/chip_example.dart';
import 'package:zeta_example/pages/theme/color_example.dart';
import 'package:zeta_example/pages/components/password_input_example.dart';
import 'package:zeta_example/pages/components/progress_example.dart';
import 'package:zeta_example/pages/assets/icons_example.dart';
import 'package:zeta_example/widgets.dart';
import 'package:zeta_flutter/zeta_flutter.dart';
Expand All @@ -30,7 +31,9 @@ final List<Component> components = [
Component(ButtonExample.name, (context) => const ButtonExample()),
Component(CheckBoxExample.name, (context) => const CheckBoxExample()),
Component(ChipExample.name, (context) => const ChipExample()),
Component(PasswordInputExample.name, (context) => const PasswordInputExample()),
Component(
PasswordInputExample.name, (context) => const PasswordInputExample()),
Component(ProgressExample.name, (context) => const ProgressExample())
];

final List<Component> theme = [
Expand Down Expand Up @@ -92,21 +95,27 @@ class _HomeState extends State<Home> {
title: Text('Widgets'),
backgroundColor: Zeta.of(context).colors.warm.shade30,
children: _components
.map((item) => ListTile(title: Text(item.name), onTap: () => context.go('/${item.name}')))
.map((item) => ListTile(
title: Text(item.name),
onTap: () => context.go('/${item.name}')))
.toList(),
),
ExpansionTile(
title: Text('Theme'),
backgroundColor: Zeta.of(context).colors.warm.shade30,
children: _theme
.map((item) => ListTile(title: Text(item.name), onTap: () => context.go('/${item.name}')))
.map((item) => ListTile(
title: Text(item.name),
onTap: () => context.go('/${item.name}')))
.toList(),
),
ExpansionTile(
title: Text('Assets'),
backgroundColor: Zeta.of(context).colors.warm.shade30,
children: _assets
.map((item) => ListTile(title: Text(item.name), onTap: () => context.go('/${item.name}')))
.map((item) => ListTile(
title: Text(item.name),
onTap: () => context.go('/${item.name}')))
.toList(),
),
],
Expand Down
51 changes: 51 additions & 0 deletions example/lib/pages/components/progress_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
import 'package:zeta_example/widgets.dart';
import 'package:zeta_flutter/zeta_flutter.dart';

class ProgressExample extends StatefulWidget {
static const String name = 'Progress';

const ProgressExample({super.key});

@override
State<ProgressExample> createState() => ProgressExampleState();
}

class ProgressExampleState extends State<ProgressExample> {
GlobalKey key = GlobalKey();

///Function to increase percentage of progress.
void increasePercentage() {
final circle = key.currentState as ProgressCircleState;
circle.increasePercentage(circle.progress + 0.1);
}

@override
Widget build(BuildContext context) {
return ExampleScaffold(
name: 'Progress',
child: Center(
child: SingleChildScrollView(
child: SizedBox(
width: double.infinity,
child: Row(
// Replace with a Column for vertical
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ProgressCircle(
progress: 0,
key: key,
size: CircleSizes.xl,
border: ZetaWidgetBorder.sharp,
),
const SizedBox(width: 20),
FilledButton(
onPressed: increasePercentage, child: Text("Increase")),
],
),
),
),
),
);
}
}
178 changes: 178 additions & 0 deletions lib/src/components/progress/progress_circle.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import '../../../zeta_flutter.dart';

/// Sizes for [ProgressCircle]
enum CircleSizes {
///24 X 24
xs,

/// 36 X 36
s,

/// 40 x 40
m,

/// 48 X 48
l,

/// 64 X 64
xl
}

///Class definition for [ProgressCircle]
class ProgressCircle extends StatefulWidget {
/// Constructor for [ProgressCircle]
const ProgressCircle({
super.key,
this.progress = 0,
this.size = CircleSizes.xl,
this.border = ZetaWidgetBorder.rounded,
});

/// Progress as a decimal value to represent percenage. 0.5 = 50%
final double progress;

///Size of [ProgressCircle]
final CircleSizes size;

/// Border Type for [ZetaWidgetBorder]
final ZetaWidgetBorder border;

@override
State<ProgressCircle> createState() => ProgressCircleState();

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(EnumProperty<CircleSizes>('size', size))
..add(DoubleProperty('progress', progress))
..add(EnumProperty<ZetaWidgetBorder>('border', border));
}
}

///Class definition for [ProgressCircleState]
class ProgressCircleState extends State<ProgressCircle>
with SingleTickerProviderStateMixin {
/// Progress percentage as decimal
double progress = 0;

///Animation controller for [ProgressCircleState]
late AnimationController controller;

///Animation for [ProgressCircleState]
late Animation<double> animation;

@override
void initState() {
super.initState();
progress = widget.progress;
controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 200));
animation = Tween<double>(
begin: widget.progress, // Start value
end: widget.progress, // End value (initially same as start value)
).animate(controller)
..addListener(() {
setState(() {
progress = animation.value;
});
});
}

@override
void dispose() {
controller.dispose();
super.dispose();
}

///Increase the progress percentage and animate to new progress percentage.
void increasePercentage(double newProgress) {
// Update the Tween with new start and end values
animation = Tween<double>(
begin: progress,
end: newProgress,
).animate(controller);
controller.forward(
from: progress); // Start the animation from the beginning
}

@override
Widget build(BuildContext context) {
return Row(
children: [
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return CustomPaint(
size: _getSize(),
painter: CirclePainter(
progress: animation.value,
rounded: widget.border == ZetaWidgetBorder.rounded,
),
);
},
),
const SizedBox(width: 20),
// FilledButton(onPressed: increasePercentage, child: Text("Increase")),
],
);
}

Size _getSize() {
switch (widget.size) {
case CircleSizes.xs:
return const Size(24, 24);
case CircleSizes.s:
return const Size(36, 36);
case CircleSizes.m:
return const Size(40, 40);
case CircleSizes.l:
return const Size(48, 48);
case CircleSizes.xl:
return const Size(64, 64);
}
}

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DoubleProperty('progress', progress))
..add(DiagnosticsProperty<AnimationController>('controller', controller))
..add(DiagnosticsProperty<Animation<double>>('animation', animation));
}
}

///Class definition for [CirclePainter]
class CirclePainter extends CustomPainter {
///Constructor for [CirclePainter]
CirclePainter({this.progress = 0, this.rounded = true});

///Percentage of progress in decimal value, defaults to 0
final double progress;

///Is circle rounded, defaults to true
final bool rounded;

final _paint = Paint()
..color = Colors.blue
..strokeWidth = 4
..style = PaintingStyle.stroke;

@override
void paint(Canvas canvas, Size size) {
if (rounded) _paint.strokeCap = StrokeCap.round;

const double fullCircle = 2 * math.pi;

canvas.drawArc(Rect.fromLTRB(0, 0, size.width, size.height),
3 * math.pi / 2, progress * fullCircle, false, _paint);
}

@override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
1 change: 1 addition & 0 deletions lib/zeta_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export 'src/components/buttons/fab.dart';
export 'src/components/checkbox/checkbox.dart';
export 'src/components/chips/chip.dart';
export 'src/components/password/password_input.dart';
export 'src/components/progress/progress_circle.dart';
export 'src/theme/color_extensions.dart';
export 'src/theme/color_scheme.dart';
export 'src/theme/color_swatch.dart';
Expand Down

0 comments on commit 675ab6d

Please sign in to comment.