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.
121 lines
3.3 KiB
Dart
121 lines
3.3 KiB
Dart
import 'package:fluffychat/config/app_config.dart';
|
|
import 'package:fluffychat/config/themes.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
class AnimatedLevelBar extends StatefulWidget {
|
|
final double height;
|
|
final double beginWidth;
|
|
final double endWidth;
|
|
final Color primaryColor;
|
|
final Color highlightColor;
|
|
|
|
const AnimatedLevelBar({
|
|
super.key,
|
|
required this.height,
|
|
required this.beginWidth,
|
|
required this.endWidth,
|
|
required this.primaryColor,
|
|
required this.highlightColor,
|
|
});
|
|
|
|
@override
|
|
AnimatedLevelBarState createState() => AnimatedLevelBarState();
|
|
}
|
|
|
|
class AnimatedLevelBarState extends State<AnimatedLevelBar>
|
|
with SingleTickerProviderStateMixin {
|
|
late AnimationController _controller;
|
|
|
|
/// Whether the animation has run for the first time during initState. Don't
|
|
/// want the animation to run when the widget mounts, only when points are gained.
|
|
bool _init = true;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_controller = AnimationController(
|
|
vsync: this,
|
|
duration: FluffyThemes.animationDuration,
|
|
);
|
|
|
|
_controller.forward().then((_) => _init = false);
|
|
}
|
|
|
|
@override
|
|
void didUpdateWidget(covariant AnimatedLevelBar oldWidget) {
|
|
super.didUpdateWidget(oldWidget);
|
|
if (oldWidget.endWidth != widget.endWidth) {
|
|
_controller.reset();
|
|
_controller.forward();
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
Animation<double> get _animation {
|
|
// If this is the first run of the animation, don't animate. This is just the widget mounting,
|
|
// not a points gain. This could instead be 'if going from 0 to a non-zero value', but that
|
|
// would remove the animation for first points gained. It would remove the need for a flag though.
|
|
if (_init) {
|
|
return Tween<double>(
|
|
begin: widget.endWidth,
|
|
end: widget.endWidth,
|
|
).animate(_controller);
|
|
}
|
|
|
|
// animate the width of the bar
|
|
return Tween<double>(
|
|
begin: widget.beginWidth,
|
|
end: widget.endWidth,
|
|
).animate(_controller);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AnimatedBuilder(
|
|
animation: _animation,
|
|
builder: (context, child) {
|
|
return Stack(
|
|
children: [
|
|
Container(
|
|
height: widget.height,
|
|
width: _animation.value,
|
|
decoration: BoxDecoration(
|
|
color: widget.primaryColor,
|
|
borderRadius: const BorderRadius.all(
|
|
Radius.circular(AppConfig.borderRadius),
|
|
),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.2),
|
|
spreadRadius: 0,
|
|
blurRadius: 5,
|
|
offset: const Offset(5, 0),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Positioned(
|
|
top: 2,
|
|
child: Container(
|
|
height: 6,
|
|
width: _animation.value >= 8 ? _animation.value - 8 : 0,
|
|
decoration: BoxDecoration(
|
|
color: widget.highlightColor,
|
|
borderRadius: const BorderRadius.all(
|
|
Radius.circular(AppConfig.borderRadius),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|