|
|
@ -6,12 +6,33 @@ import 'package:flutter/scheduler.dart';
|
|
|
|
const halfPi = pi / 2;
|
|
|
|
const halfPi = pi / 2;
|
|
|
|
const pi = math.pi;
|
|
|
|
const pi = math.pi;
|
|
|
|
|
|
|
|
|
|
|
|
typedef LabelBuilder = Widget Function(double value);
|
|
|
|
typedef LabelBuilder = Iterable<Widget> Function(List<LevelValue> values);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extension LevelValueExt on List<LevelValue> {
|
|
|
|
|
|
|
|
double? level(int level) {
|
|
|
|
|
|
|
|
for (var element in this) {
|
|
|
|
|
|
|
|
if (element.level == level) return element.value;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@immutable
|
|
|
|
|
|
|
|
class LevelValue {
|
|
|
|
|
|
|
|
final double value;
|
|
|
|
|
|
|
|
final int level;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const LevelValue(this.value) : level = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const LevelValue._withLevel(this.value, this.level);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LevelValue incrementLevel() => LevelValue._withLevel(value, level + 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class RingIndicator extends StatefulWidget {
|
|
|
|
class RingIndicator extends StatefulWidget {
|
|
|
|
const RingIndicator({
|
|
|
|
const RingIndicator({
|
|
|
|
Key? key,
|
|
|
|
Key? key,
|
|
|
|
this.backgroundColor = Colors.grey,
|
|
|
|
this.backgroundColor = Colors.white12,
|
|
|
|
this.ringWidth = 10,
|
|
|
|
this.ringWidth = 10,
|
|
|
|
this.startAngel = 0,
|
|
|
|
this.startAngel = 0,
|
|
|
|
this.endAngel = pi * 2,
|
|
|
|
this.endAngel = pi * 2,
|
|
|
@ -21,7 +42,9 @@ class RingIndicator extends StatefulWidget {
|
|
|
|
required this.value,
|
|
|
|
required this.value,
|
|
|
|
this.innerRing,
|
|
|
|
this.innerRing,
|
|
|
|
this.labelBuilder,
|
|
|
|
this.labelBuilder,
|
|
|
|
}) : super(key: key);
|
|
|
|
double? gap,
|
|
|
|
|
|
|
|
}) : gap = gap ?? ringWidth / 2,
|
|
|
|
|
|
|
|
super(key: key);
|
|
|
|
|
|
|
|
|
|
|
|
final Color backgroundColor;
|
|
|
|
final Color backgroundColor;
|
|
|
|
final double ringWidth;
|
|
|
|
final double ringWidth;
|
|
|
@ -33,19 +56,22 @@ class RingIndicator extends StatefulWidget {
|
|
|
|
final double value;
|
|
|
|
final double value;
|
|
|
|
final RingIndicator? innerRing;
|
|
|
|
final RingIndicator? innerRing;
|
|
|
|
final LabelBuilder? labelBuilder;
|
|
|
|
final LabelBuilder? labelBuilder;
|
|
|
|
|
|
|
|
final double gap;
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
@override
|
|
|
|
State<RingIndicator> createState() => _RingIndicatorState();
|
|
|
|
State<RingIndicator> createState() => _RingIndicatorState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _RingIndicatorState extends State<RingIndicator> {
|
|
|
|
class _RingIndicatorState extends State<RingIndicator> {
|
|
|
|
double? _value = 0;
|
|
|
|
double _value = 0;
|
|
|
|
|
|
|
|
Map<int, LevelValue> values = {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_RingIndicatorState? parent;
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
var value = _value ?? widget.value;
|
|
|
|
|
|
|
|
var fillAngel =
|
|
|
|
var fillAngel =
|
|
|
|
((value - widget.minValue) / (widget.maxValue - widget.minValue)) * (widget.endAngel - widget.startAngel);
|
|
|
|
((_value - widget.minValue) / (widget.maxValue - widget.minValue)) * (widget.endAngel - widget.startAngel);
|
|
|
|
return Center(
|
|
|
|
return Center(
|
|
|
|
child: SizedBox.expand(
|
|
|
|
child: SizedBox.expand(
|
|
|
|
child: CustomPaint(
|
|
|
|
child: CustomPaint(
|
|
|
@ -59,7 +85,12 @@ class _RingIndicatorState extends State<RingIndicator> {
|
|
|
|
),
|
|
|
|
),
|
|
|
|
child: Stack(
|
|
|
|
child: Stack(
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
if (widget.labelBuilder != null) widget.labelBuilder!(value),
|
|
|
|
if (widget.innerRing != null)
|
|
|
|
|
|
|
|
Padding(
|
|
|
|
|
|
|
|
padding: EdgeInsets.all(widget.ringWidth + widget.gap),
|
|
|
|
|
|
|
|
child: widget.innerRing,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
if (widget.labelBuilder != null) ...widget.labelBuilder!(values.values.toList()),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
@ -69,9 +100,7 @@ class _RingIndicatorState extends State<RingIndicator> {
|
|
|
|
|
|
|
|
|
|
|
|
Ticker? ticker;
|
|
|
|
Ticker? ticker;
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
_handleValueChange(double newValue, double oldValue) {
|
|
|
|
void didUpdateWidget(RingIndicator oldWidget) {
|
|
|
|
|
|
|
|
super.didUpdateWidget(oldWidget);
|
|
|
|
|
|
|
|
var startTime = DateTime.now();
|
|
|
|
var startTime = DateTime.now();
|
|
|
|
ticker?.stop();
|
|
|
|
ticker?.stop();
|
|
|
|
ticker = Ticker((_) {
|
|
|
|
ticker = Ticker((_) {
|
|
|
@ -81,12 +110,43 @@ class _RingIndicatorState extends State<RingIndicator> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mounted) {
|
|
|
|
if (mounted) {
|
|
|
|
setState(() {
|
|
|
|
setState(() {
|
|
|
|
_value = oldWidget.value + (widget.value - oldWidget.value) * (diff / 300);
|
|
|
|
_value = oldValue + (newValue - oldValue) * (diff / 300);
|
|
|
|
|
|
|
|
values[0] = LevelValue(_value);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
if (parent != null) {
|
|
|
|
|
|
|
|
for (var value in values.values) {
|
|
|
|
|
|
|
|
parent!.updateValue(value.incrementLevel());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
..start();
|
|
|
|
..start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
|
|
void initState() {
|
|
|
|
|
|
|
|
super.initState();
|
|
|
|
|
|
|
|
_handleValueChange(widget.value, 0);
|
|
|
|
|
|
|
|
parent = context.findAncestorStateOfType<_RingIndicatorState>();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
|
|
void didUpdateWidget(RingIndicator oldWidget) {
|
|
|
|
|
|
|
|
super.didUpdateWidget(oldWidget);
|
|
|
|
|
|
|
|
_handleValueChange(widget.value, oldWidget.value);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void updateValue(LevelValue value) {
|
|
|
|
|
|
|
|
values[value.level] = value;
|
|
|
|
|
|
|
|
if (parent != null && parent!.mounted) {
|
|
|
|
|
|
|
|
for (var value in values.values) {
|
|
|
|
|
|
|
|
parent!.updateValue(value.incrementLevel());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mounted) {
|
|
|
|
|
|
|
|
setState(() {});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _RingIndicatorPainter extends CustomPainter {
|
|
|
|
class _RingIndicatorPainter extends CustomPainter {
|
|
|
|