dotrix 1.0.0 copy "dotrix: ^1.0.0" to clipboard
dotrix: ^1.0.0 copied to clipboard

A Flutter dot matrix animation indicator library with 28 beautiful effects. Features customizable dot size, colors, spacing, glow effects, and animation speed.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:dotrix/dotrix.dart';

void main() {
  runApp(const DotrixDemoApp());
}

class DotrixDemoApp extends StatelessWidget {
  const DotrixDemoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dotrix Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark(useMaterial3: true),
      home: const DemoPage(),
    );
  }
}

class DemoPage extends StatefulWidget {
  const DemoPage({super.key});

  @override
  State<DemoPage> createState() => _DemoPageState();
}

class _DemoPageState extends State<DemoPage> {
  // Configuration parameters
  double dotSize = 36.0;
  double borderRadius = 0.0;
  double spacing = 0.0;
  int animationSpeed = 1200;
  Color activeColor = const Color(0xFFFFD700);
  Color inactiveColor = const Color(0xFF333333);
  double opacity = 1.0;
  Color shadowColor = const Color(0xFFFFE57F).withValues(alpha: 0.41);
  Offset shadowOffset = Offset.zero;
  double blurRadius = 11.0;
  double spreadRadius = 0.0;
  double scale = 1.0;
  Alignment scaleAlignment = Alignment.center;

  // All component types (alphabetically sorted)
  final List<({String name, Widget widget})> indicators = [
    (name: 'ArrowMove', widget: const ArrowMove()),
    (name: 'Burst', widget: const Burst()),
    (name: 'Cascade', widget: const Cascade()),
    (name: 'Chaos', widget: const Chaos()),
    (name: 'Checkerboard', widget: const Checkerboard()),
    (name: 'Clockwise', widget: const Clockwise()),
    (name: 'Converge', widget: const Converge()),
    (name: 'Corners', widget: const Corners()),
    (name: 'Cross', widget: const Cross()),
    (name: 'Diamond', widget: const Diamond()),
    (name: 'DiagonalRace', widget: const DiagonalRace()),
    (name: 'Flip', widget: const Flip()),
    (name: 'FlowDown', widget: FlowDown.random()),
    (name: 'FlowLeft', widget: FlowLeft.random()),
    (name: 'FlowRight', widget: FlowRight.random()),
    (name: 'FlowUp', widget: FlowUp.random()),
    (name: 'Inward', widget: const Inward()),
    (name: 'Pulse', widget: const Pulse()),
    (name: 'Pulse2', widget: const Pulse2()),
    (name: 'PulseRing', widget: const PulseRing()),
    (name: 'Radial', widget: const Radial()),
    (name: 'Ripple', widget: const Ripple()),
    (name: 'Scatter', widget: const Scatter()),
    (name: 'SineWave', widget: const SineWave()),
    (name: 'Spiral', widget: const Spiral()),
    (name: 'Spinner', widget: const Spinner()),
    (name: 'Wave', widget: const Wave()),
    (name: 'Zigzag', widget: const Zigzag()),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Row(
        children: [
          // Left configuration panel
          Container(
            width: 320,
            color: const Color(0xFF0A0A0A),
            child: ListView(
              padding: const EdgeInsets.all(24),
              children: [
                // Title
                const Text(
                  'Dotrix Configuration',
                  style: TextStyle(
                    fontSize: 24,
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                ),
                const SizedBox(height: 8),
                Text(
                  'Dot matrix animation indicator component library - 28 effects',
                  style: TextStyle(fontSize: 14, color: Colors.grey[400]),
                ),
                const SizedBox(height: 32),

                // Size and spacing
                _buildSectionHeader('Size & Spacing'),
                _buildSlider('Dot Size', dotSize, 8, 64, (v) {
                  setState(() => dotSize = v);
                }, suffix: 'px'),
                _buildSlider('Border Radius', borderRadius, 0, 32, (v) {
                  setState(() => borderRadius = v);
                }, suffix: 'px'),
                _buildSlider('Spacing', spacing, 0, 16, (v) {
                  setState(() => spacing = v);
                }, suffix: 'px'),
                _buildSlider('Scale', scale * 100, 50, 150, (v) {
                  setState(() => scale = v / 100);
                }, suffix: '%'),
                _buildAlignmentSelector(),
                const SizedBox(height: 24),

                // Animation parameters
                _buildSectionHeader('Animation Parameters'),
                _buildSlider(
                  'Animation Speed',
                  animationSpeed.toDouble(),
                  200,
                  3000,
                  (v) {
                    setState(() => animationSpeed = v.round());
                  },
                  suffix: 'ms',
                ),
                const SizedBox(height: 24),

                // Color properties
                _buildSectionHeader('Color Properties'),
                _buildColorPicker('Active Color', activeColor, (color) {
                  setState(() => activeColor = color);
                }),
                _buildColorPicker('Inactive Color', inactiveColor, (color) {
                  setState(() => inactiveColor = color);
                }),
                _buildSlider('Opacity', opacity * 100, 0, 100, (v) {
                  setState(() => opacity = v / 100);
                }, suffix: '%'),
                const SizedBox(height: 24),

                // Shadow properties (BoxShadow specification)
                _buildSectionHeader('Shadow Properties'),
                _buildColorPicker('Shadow Color', shadowColor, (color) {
                  setState(() => shadowColor = color);
                }),
                _buildSlider('Blur Radius', blurRadius, 0, 30, (v) {
                  setState(() => blurRadius = v);
                }, suffix: 'px'),
                _buildSlider('Spread Radius', spreadRadius, -10, 20, (v) {
                  setState(() => spreadRadius = v);
                }, suffix: 'px'),
                _buildShadowOffsetSelector(),
                const SizedBox(height: 24),
              ],
            ),
          ),

          // Divider
          Container(width: 1, color: const Color(0xFF1A1A1A)),

          // Right component display
          Expanded(
            child: Container(
              color: const Color(0xFF050505),
              child: GridView.builder(
                padding: const EdgeInsets.all(32),
                gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
                  maxCrossAxisExtent: 160,
                  crossAxisSpacing: 24,
                  mainAxisSpacing: 24,
                  childAspectRatio: 1.2,
                ),
                itemCount: indicators.length,
                itemBuilder: (context, index) {
                  final indicator = indicators[index];
                  return _buildIndicatorCard(indicator.name, indicator.widget);
                },
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildSectionHeader(String title) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 16),
      child: Text(
        title,
        style: TextStyle(
          fontSize: 12,
          fontWeight: FontWeight.bold,
          color: Colors.grey[400],
          letterSpacing: 1.0,
        ),
      ),
    );
  }

  Widget _buildSlider(
    String label,
    double value,
    double min,
    double max,
    ValueChanged<double> onChanged, {
    String suffix = '',
  }) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 20),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            children: [
              Expanded(
                child: Text(
                  label,
                  style: const TextStyle(fontSize: 13, color: Colors.white),
                  overflow: TextOverflow.ellipsis,
                ),
              ),
              const SizedBox(width: 8),
              Text(
                '${value.round()}$suffix',
                style: TextStyle(
                  fontSize: 13,
                  color: Colors.grey[400],
                  fontFamily: 'monospace',
                ),
              ),
            ],
          ),
          const SizedBox(height: 8),
          SliderTheme(
            data: SliderThemeData(
              trackHeight: 4,
              thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 8),
              overlayShape: const RoundSliderOverlayShape(overlayRadius: 16),
              activeTrackColor: activeColor,
              inactiveTrackColor: const Color(0xFF1A1A1A),
              thumbColor: activeColor,
              overlayColor: activeColor.withValues(alpha: 0.2),
              valueIndicatorColor: activeColor,
              valueIndicatorTextStyle: const TextStyle(
                color: Colors.white,
                fontSize: 12,
              ),
            ),
            child: Slider(
              value: value,
              min: min,
              max: max,
              onChanged: onChanged,
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildColorPicker(
    String label,
    Color color,
    ValueChanged<Color> onColorChanged,
  ) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 16),
      child: GestureDetector(
        onTap: () {
          debugPrint('🔍 Click color picker: $label');
          _showColorPicker(context, color, onColorChanged);
        },
        child: Row(
          children: [
            Expanded(
              child: Text(
                label,
                style: const TextStyle(fontSize: 13, color: Colors.white),
              ),
            ),
            const SizedBox(width: 8),
            Container(
              width: 28,
              height: 28,
              decoration: BoxDecoration(
                color: color,
                borderRadius: BorderRadius.circular(4),
                border: Border.all(color: Colors.white, width: 1),
              ),
            ),
            const SizedBox(width: 6),
            Container(
              padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
              decoration: BoxDecoration(
                color: const Color(0xFF1A1A1A),
                borderRadius: BorderRadius.circular(4),
              ),
              child: Text(
                '#${color.toARGB32().toRadixString(16).substring(2).toUpperCase()}',
                style: TextStyle(
                  fontSize: 11,
                  color: Colors.grey[400],
                  fontFamily: 'monospace',
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildAlignmentSelector() {
    final alignments = [
      (Alignment.topLeft, 'TopLeft'),
      (Alignment.topCenter, 'TopCenter'),
      (Alignment.topRight, 'TopRight'),
      (Alignment.centerLeft, 'CenterLeft'),
      (Alignment.center, 'Center'),
      (Alignment.centerRight, 'CenterRight'),
      (Alignment.bottomLeft, 'BottomLeft'),
      (Alignment.bottomCenter, 'BottomCenter'),
      (Alignment.bottomRight, 'BottomRight'),
    ];

    return Padding(
      padding: const EdgeInsets.only(bottom: 20),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            'Scale Alignment',
            style: const TextStyle(fontSize: 13, color: Colors.white),
          ),
          const SizedBox(height: 8),
          Wrap(
            spacing: 6,
            runSpacing: 6,
            children: alignments.map((alignment) {
              final isSelected = alignment.$1 == scaleAlignment;
              return InkWell(
                onTap: () {
                  setState(() => scaleAlignment = alignment.$1);
                },
                child: Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 10,
                    vertical: 6,
                  ),
                  decoration: BoxDecoration(
                    color: isSelected ? activeColor : const Color(0xFF1A1A1A),
                    borderRadius: BorderRadius.circular(4),
                    border: Border.all(
                      color: isSelected ? activeColor : const Color(0xFF2A2A2A),
                      width: 1,
                    ),
                  ),
                  child: Text(
                    alignment.$2,
                    style: TextStyle(
                      fontSize: 11,
                      color: isSelected ? Colors.black : Colors.grey[400],
                      fontWeight: isSelected
                          ? FontWeight.w600
                          : FontWeight.normal,
                    ),
                  ),
                ),
              );
            }).toList(),
          ),
        ],
      ),
    );
  }

  Widget _buildShadowOffsetSelector() {
    final offsets = [
      (Offset(-4, -4), '↖ Top Left'),
      (Offset(0, -4), '↑ Top'),
      (Offset(4, -4), '↗ Top Right'),
      (Offset(-4, 0), '← Left'),
      (Offset.zero, '● No Offset'),
      (Offset(4, 0), '→ Right'),
      (Offset(-4, 4), '↙ Bottom Left'),
      (Offset(0, 4), '↓ Bottom'),
      (Offset(4, 4), '↘ Bottom Right'),
    ];

    return Padding(
      padding: const EdgeInsets.only(bottom: 20),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            'Shadow Offset',
            style: const TextStyle(fontSize: 13, color: Colors.white),
          ),
          const SizedBox(height: 8),
          Wrap(
            spacing: 6,
            runSpacing: 6,
            children: offsets.map((offsetData) {
              final isSelected = offsetData.$1 == shadowOffset;
              return InkWell(
                onTap: () {
                  setState(() => shadowOffset = offsetData.$1);
                },
                child: Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 10,
                    vertical: 6,
                  ),
                  decoration: BoxDecoration(
                    color: isSelected ? activeColor : const Color(0xFF1A1A1A),
                    borderRadius: BorderRadius.circular(4),
                    border: Border.all(
                      color: isSelected ? activeColor : const Color(0xFF2A2A2A),
                      width: 1,
                    ),
                  ),
                  child: Text(
                    offsetData.$2,
                    style: TextStyle(
                      fontSize: 11,
                      color: isSelected ? Colors.black : Colors.grey[400],
                      fontWeight: isSelected
                          ? FontWeight.w600
                          : FontWeight.normal,
                    ),
                  ),
                ),
              );
            }).toList(),
          ),
        ],
      ),
    );
  }

  Widget _buildIndicatorCard(String name, Widget widget) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        // Component with current configuration applied (responsive size)
        Flexible(
          child: FittedBox(fit: BoxFit.contain, child: _applyConfig(widget)),
        ),
        const SizedBox(height: 8),
        Text(
          name,
          style: const TextStyle(
            fontSize: 12,
            fontWeight: FontWeight.w500,
            color: Colors.white,
          ),
        ),
      ],
    );
  }

  Widget _applyConfig(Widget widget) {
    // Apply configuration based on component type (alphabetically)
    if (widget is ArrowMove) {
      return ArrowMove(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Burst) {
      return Burst(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Cascade) {
      return Cascade(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Chaos) {
      return Chaos(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Checkerboard) {
      return Checkerboard(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Clockwise) {
      return Clockwise(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Converge) {
      return Converge(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Corners) {
      return Corners(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Cross) {
      return Cross(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Diamond) {
      return Diamond(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is DiagonalRace) {
      return DiagonalRace(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Flip) {
      return Flip(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is FlowDown) {
      return FlowDown(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is FlowLeft) {
      return FlowLeft(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is FlowRight) {
      return FlowRight(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is FlowUp) {
      return FlowUp(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Inward) {
      return Inward(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Pulse) {
      return Pulse(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Pulse2) {
      return Pulse2(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is PulseRing) {
      return PulseRing(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Radial) {
      return Radial(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Ripple) {
      return Ripple(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Scatter) {
      return Scatter(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is SineWave) {
      return SineWave(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Spiral) {
      return Spiral(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Spinner) {
      return Spinner(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Wave) {
      return Wave(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }
    if (widget is Zigzag) {
      return Zigzag(
        dotSize: dotSize,
        borderRadius: borderRadius,
        spacing: spacing,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        opacity: opacity,
        shadowColor: shadowColor,
        shadowOffset: shadowOffset,
        blurRadius: blurRadius,
        spreadRadius: spreadRadius,
        animationSpeed: Duration(milliseconds: animationSpeed),
        scale: scale,
        scaleAlignment: scaleAlignment,
      );
    }

    return widget;
  }

  void _showColorPicker(
    BuildContext context,
    Color currentColor,
    ValueChanged<Color> onColorChanged,
  ) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        backgroundColor: const Color(0xFF1A1A1A),
        title: const Text(
          'Select Color',
          style: TextStyle(color: Colors.white),
        ),
        content: SingleChildScrollView(
          child: _DotrixColorPicker(
            color: currentColor,
            onColorChanged: onColorChanged,
          ),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Done', style: TextStyle(color: Colors.white)),
          ),
        ],
      ),
    );
  }
}

// Simplified color picker (privatized naming to avoid conflicts)
class _DotrixColorPicker extends StatefulWidget {
  final Color color;
  final ValueChanged<Color> onColorChanged;

  const _DotrixColorPicker({required this.color, required this.onColorChanged});

  @override
  State<_DotrixColorPicker> createState() => _DotrixColorPickerState();
}

class _DotrixColorPickerState extends State<_DotrixColorPicker> {
  late Color selectedColor;

  // Preset colors
  static const presetColors = [
    Color(0xFFFFD700), // Gold
    Color(0xFFFFE57F), // Light Gold
    Color(0xFFD4AF37), // Classic Gold
    Color(0xFFC9B037), // Champagne
    Color(0xFF6366F1), // Indigo
    Color(0xFF8B5CF6), // Violet
    Color(0xFF10B981), // Emerald
    Color(0xFF3B82F6), // Blue
    Color(0xFFF59E0B), // Amber
    Color(0xFFEF4444), // Red
    Color(0xFF333333), // Dark Grey
    Color(0xFFFFFFFF), // White
  ];

  @override
  void initState() {
    super.initState();
    selectedColor = widget.color;
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        // Preset color grid (use Wrap instead of GridView to avoid Viewport issues)
        Wrap(
          spacing: 8,
          runSpacing: 8,
          children: presetColors.map((color) {
            final isSelected = color.toARGB32() == selectedColor.toARGB32();
            return InkWell(
              onTap: () {
                setState(() => selectedColor = color);
                widget.onColorChanged(color);
              },
              child: SizedBox(
                width: 60,
                height: 60,
                child: Container(
                  decoration: BoxDecoration(
                    color: color,
                    borderRadius: BorderRadius.circular(8),
                    border: Border.all(
                      color: isSelected ? Colors.white : Colors.transparent,
                      width: 2,
                    ),
                  ),
                ),
              ),
            );
          }).toList(),
        ),
        const SizedBox(height: 16),
        // Custom color sliders
        _buildColorSlider(
          'Red',
          (selectedColor.r * 255.0).round().clamp(0, 255),
          (value) {
            setState(() {
              selectedColor = Color.fromRGBO(
                value.round().clamp(0, 255),
                (selectedColor.g * 255.0).round().clamp(0, 255),
                (selectedColor.b * 255.0).round().clamp(0, 255),
                selectedColor.a,
              );
              widget.onColorChanged(selectedColor);
            });
          },
        ),
        _buildColorSlider(
          'Green',
          (selectedColor.g * 255.0).round().clamp(0, 255),
          (value) {
            setState(() {
              selectedColor = Color.fromRGBO(
                (selectedColor.r * 255.0).round().clamp(0, 255),
                value.round().clamp(0, 255),
                (selectedColor.b * 255.0).round().clamp(0, 255),
                selectedColor.a,
              );
              widget.onColorChanged(selectedColor);
            });
          },
        ),
        _buildColorSlider(
          'Blue',
          (selectedColor.b * 255.0).round().clamp(0, 255),
          (value) {
            setState(() {
              selectedColor = Color.fromRGBO(
                (selectedColor.r * 255.0).round().clamp(0, 255),
                (selectedColor.g * 255.0).round().clamp(0, 255),
                value.round().clamp(0, 255),
                selectedColor.a,
              );
              widget.onColorChanged(selectedColor);
            });
          },
        ),
      ],
    );
  }

  Widget _buildColorSlider(
    String label,
    int value,
    ValueChanged<double> onChanged,
  ) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 12),
      child: Row(
        children: [
          SizedBox(
            width: 40,
            child: Text(
              label,
              style: const TextStyle(fontSize: 12, color: Colors.white70),
            ),
          ),
          Expanded(
            child: Slider(
              value: value.toDouble(),
              min: 0,
              max: 255,
              onChanged: onChanged,
            ),
          ),
          SizedBox(
            width: 30,
            child: Text(
              value.toString(),
              style: const TextStyle(
                fontSize: 12,
                color: Colors.white70,
                fontFamily: 'monospace',
              ),
              textAlign: TextAlign.right,
            ),
          ),
        ],
      ),
    );
  }
}
1
likes
160
points
77
downloads

Publisher

verified publisherfluttercandies.com

Weekly Downloads

A Flutter dot matrix animation indicator library with 28 beautiful effects. Features customizable dot size, colors, spacing, glow effects, and animation speed.

Repository (GitHub)
View/report issues

Topics

#ui #widget #animation #indicator #loading

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on dotrix