Skip to content

Instantly share code, notes, and snippets.

@tensor-programming
Last active January 5, 2022 22:10
Show Gist options
  • Save tensor-programming/8d41c2af5170bb9960bbec1c920f9ee2 to your computer and use it in GitHub Desktop.
Save tensor-programming/8d41c2af5170bb9960bbec1c920f9ee2 to your computer and use it in GitHub Desktop.
flutter timer with increment button
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() => runApp(MaterialApp(
home: const MyApp(),
theme: ThemeData.dark(),
));
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> with TickerProviderStateMixin {
late AnimationController controller;
late Duration duration;
late TimerPainter painter;
// bool isPlaying = false;
String get timerString {
Duration duration = controller.duration! * controller.value;
return '${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}';
}
@override
void initState() {
super.initState();
duration = const Duration(seconds: 10);
controller = AnimationController(
vsync: this,
duration: duration,
);
painter = TimerPainter(
animation: controller,
backgroundColor: Colors.white,
color: Colors.greenAccent,
);
}
@override
Widget build(BuildContext context) {
ThemeData themeData = Theme.of(context);
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Align(
alignment: FractionalOffset.center,
child: AspectRatio(
aspectRatio: 1.0,
child: Stack(
children: <Widget>[
Positioned.fill(
child: AnimatedBuilder(
animation: controller,
builder: (BuildContext context, Widget? child) {
return CustomPaint(painter: painter);
},
),
),
Align(
alignment: FractionalOffset.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
"Count Down",
style: themeData.textTheme.bodyMedium,
),
AnimatedBuilder(
animation: controller,
builder: (BuildContext context, Widget? child) {
return Text(
timerString,
style: themeData.textTheme.bodyLarge,
);
}),
],
),
),
],
),
),
),
),
Container(
margin: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FloatingActionButton(
child: AnimatedBuilder(
animation: controller,
builder: (BuildContext context, Widget? child) {
return Icon(controller.isAnimating
? Icons.pause
: Icons.play_arrow);
// Icon(isPlaying
// ? Icons.pause
// : Icons.play_arrow);
},
),
onPressed: () {
// setState(() => isPlaying = !isPlaying);
if (controller.isAnimating) {
controller.stop(canceled: true);
} else {
controller.reverse(
from: controller.value == 0.0
? 1.0
: controller.value);
}
},
),
FloatingActionButton(
onPressed: () {
setState(() {
var incrValue = 5;
var incrDur = Duration(seconds: incrValue);
// calculate the current duration.
var currentDur =
controller.duration! * controller.value;
// increment the duration by 5 seconds.
var newDur = currentDur + incrDur;
// calculate the total duration of the animation plus the incremented value.
var totalDur = controller.duration! + incrDur;
// calculate the new animation value.
var newValue = newDur.inSeconds / totalDur.inSeconds;
controller.duration = totalDur;
controller.value = newValue;
// Restart Animation.
controller.reverse(
from: controller.value == 0.0
? 1.0
: controller.value);
});
},
child: const Icon(Icons.add_alarm),
)
],
),
)
],
),
),
);
}
}
class TimerPainter extends CustomPainter {
TimerPainter({
required this.animation,
required this.backgroundColor,
required this.color,
}) : super(repaint: animation);
final Animation<double> animation;
final Color backgroundColor, color;
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = backgroundColor
..strokeWidth = 5.0
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke;
canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
paint.color = color;
double progress = (1.0 - animation.value) * 2 * math.pi;
canvas.drawArc(Offset.zero & size, math.pi * 1.5, -progress, false, paint);
}
@override
bool shouldRepaint(TimerPainter oldDelegate) {
return animation.value != oldDelegate.animation.value ||
color != oldDelegate.color ||
backgroundColor != oldDelegate.backgroundColor;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment