Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ class _DotIndicatorStoryState extends State<DotIndicatorStory> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
MoonDotIndicator(
selectedDot: _selectedDot,
dotCount: 4,
selectedDot: _selectedDot,
size: sizeKnob?.toDouble(),
gap: gapKnob?.toDouble(),
selectedColor: selectedColor,
Expand All @@ -75,7 +75,7 @@ class _DotIndicatorStoryState extends State<DotIndicatorStory> {
children: List.generate(
4,
(int index) => Padding(
padding: EdgeInsets.only(right: index != 3 ? 8.0 : 0),
padding: const EdgeInsets.symmetric(horizontal: 4),
child: MoonFilledButton(
label: Text("${index + 1}"),
onTap: () => setState(() => _selectedDot = index),
Expand Down
129 changes: 32 additions & 97 deletions lib/src/widgets/dot_indicator/dot_indicator.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import 'package:flutter/material.dart';

import 'package:mix/mix.dart';
import 'package:moon_core/moon_core.dart';

import 'package:moon_design/src/theme/theme.dart';
import 'package:moon_design/src/theme/tokens/sizes.dart';
import 'package:moon_design/src/theme/tokens/transitions.dart';

import 'package:moon_tokens/moon_tokens.dart';

class MoonDotIndicator extends StatefulWidget {
class MoonDotIndicator extends StatelessWidget {
/// The color of the selected dot.
final Color? selectedColor;

Expand Down Expand Up @@ -45,112 +45,47 @@ class MoonDotIndicator extends StatefulWidget {
required this.dotCount,
});

@override
_CarouselIndicatorState createState() => _CarouselIndicatorState();
}

class _CarouselIndicatorState extends State<MoonDotIndicator>
with TickerProviderStateMixin {
final ColorTweenWithPremultipliedAlpha _dotColorTween =
ColorTweenWithPremultipliedAlpha();

List<AnimationController>? _animationControllers;
List<Animation<Color?>>? _animations;

@override
void initState() {
super.initState();

WidgetsBinding.instance.addPostFrameCallback((Duration _) {
_animationControllers![widget.selectedDot].forward();
});
}

@override
void didUpdateWidget(MoonDotIndicator oldWidget) {
super.didUpdateWidget(oldWidget);

if (widget.selectedDot != oldWidget.selectedDot) {
_animationControllers![oldWidget.selectedDot].reverse();
_animationControllers![widget.selectedDot].forward();
}
}

@override
void dispose() {
for (final controller in _animationControllers!) {
controller.dispose();
}

super.dispose();
}

@override
Widget build(BuildContext context) {
final double effectiveSize = widget.size ??
context.moonTheme?.dotIndicatorTheme.properties.size ??
MoonSizes.sizes.x4s;
final double effectiveSize = size ?? MoonSizes.sizes.x4s;

final double effectiveGap = widget.gap ??
context.moonTheme?.dotIndicatorTheme.properties.gap ??
MoonSizes.sizes.x4s;
final double effectiveGap = gap ?? MoonSizes.sizes.x4s;

final Color effectiveSelectedColor = widget.selectedColor ??
context.moonTheme?.dotIndicatorTheme.colors.selectedColor ??
MoonColors.light.piccolo;
final Color effectiveSelectedColor =
selectedColor ?? MoonColors.light.piccolo;

final Color effectiveUnselectedColor = widget.unselectedColor ??
context.moonTheme?.dotIndicatorTheme.colors.unselectedColor ??
MoonColors.light.beerus;
final Color effectiveUnselectedColor =
unselectedColor ?? MoonColors.light.beerus;

final Duration effectiveTransitionDuration = widget.transitionDuration ??
context.moonTheme?.dotIndicatorTheme.properties.transitionDuration ??
final Duration effectiveTransitionDuration = transitionDuration ??
MoonTransitions.transitions.defaultTransitionDuration;

final Curve effectiveTransitionCurve = widget.transitionCurve ??
context.moonTheme?.dotIndicatorTheme.properties.transitionCurve ??
MoonTransitions.transitions.defaultTransitionCurve;

_animationControllers ??= List.generate(
widget.dotCount,
(index) => AnimationController(
duration: effectiveTransitionDuration,
vsync: this,
),
);
final Curve effectiveTransitionCurve =
transitionCurve ?? MoonTransitions.transitions.defaultTransitionCurve;

_animations ??= List.generate(
widget.dotCount,
(index) => _animationControllers![index].drive(
_dotColorTween.chain(CurveTween(curve: effectiveTransitionCurve)),
),
final Style dotIndicatorStyle = Style(
$flex.chain
..gap(effectiveGap)
..mainAxisAlignment.center(),
);

_dotColorTween
..begin = effectiveUnselectedColor
..end = effectiveSelectedColor;

return RepaintBoundary(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List<Widget>.generate(
widget.dotCount,
(int index) => AnimatedBuilder(
animation: _animations![index],
builder: (BuildContext context, Widget? _) {
return Container(
width: effectiveSize,
height: effectiveSize,
margin: EdgeInsets.symmetric(horizontal: effectiveGap / 2),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _animations![index].value,
),
);
},
),
),
),
Style dotStyle(Color color) => Style(
$box.chain
..width(effectiveSize)
..height(effectiveSize)
..color(color)
..shape.circle(),
);

return MoonRawDotIndicator(
dotCount: dotCount,
selectedDot: selectedDot,
selectedColor: effectiveSelectedColor,
unselectedColor: effectiveUnselectedColor,
transitionDuration: effectiveTransitionDuration,
transitionCurve: effectiveTransitionCurve,
dotIndicatorStyle: dotIndicatorStyle,
dotBuilder: (int _, Color color) => Box(style: dotStyle(color)),
);
}
}