dot_matrix_widget 0.1.1 copy "dot_matrix_widget: ^0.1.1" to clipboard
dot_matrix_widget: ^0.1.1 copied to clipboard

Render any widget as a customizable dot-matrix display in Flutter.

example/lib/main.dart

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

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

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

  @override
  Widget build(BuildContext context) {
    const Color scaffoldColor = Color(0xFF08090D);
    const Color surfaceColor = Color(0xFF0F1218);

    final ColorScheme scheme = const ColorScheme.dark().copyWith(
      primary: Colors.cyanAccent,
      onPrimary: Colors.black,
      secondary: const Color(0xFF8E44FF),
      onSecondary: Colors.white,
      error: Colors.redAccent,
      onError: Colors.black,
      surface: surfaceColor,
      onSurface: Colors.white,
    );

    return MaterialApp(
      title: 'Dot Matrix Widget Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        brightness: Brightness.dark,
        colorScheme: scheme,
        scaffoldBackgroundColor: scaffoldColor,
        useMaterial3: true,
      ),
      home: const DotMatrixDemoPage(),
    );
  }
}

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

  @override
  State<DotMatrixDemoPage> createState() => _DotMatrixDemoPageState();
}

class _DotMatrixDemoPageState extends State<DotMatrixDemoPage> {
  static const Map<String, Color> _singleColorOptions = {
    'Cyan': Color(0xFF4DF3FF),
    'Amber': Color(0xFFFFB84D),
    'Magenta': Color(0xFFE94CFF),
    'Lime': Color(0xFF5CFF6A),
  };

  static final Map<String, DotMatrixStylePreset Function()> _presetFactories = {
    'LED Panel': DotMatrixStylePreset.ledPanel,
    'Analog TV': DotMatrixStylePreset.analogTv,
    'Vintage Amber': DotMatrixStylePreset.vintageAmber,
  };

  DotShapeType _shape = DotShapeType.circle;
  DotColorMode _colorMode = DotColorMode.original;
  double _dotSize = 6;
  double _spacing = 2;
  String _singleColorKey = _singleColorOptions.keys.first;
  String _presetKey = _presetFactories.keys.first;

  Color get _selectedSingleColor => _singleColorOptions[_singleColorKey]!;

  DotMatrixStylePreset? get _selectedPreset {
    final factory = _presetFactories[_presetKey];
    return factory?.call();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Dot Matrix Widget Demo'),
        backgroundColor: Colors.transparent,
        elevation: 0,
      ),
      body: SafeArea(
        child: SingleChildScrollView(
          padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              _buildPreview(context),
              const SizedBox(height: 32),
              _buildControls(context),
              const SizedBox(height: 32),
              _buildGallery(context),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildPreview(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('Live preview', style: Theme.of(context).textTheme.titleLarge),
        const SizedBox(height: 12),
        AspectRatio(
          aspectRatio: 16 / 9,
          child: ClipRRect(
            borderRadius: BorderRadius.circular(24),
            child: DecoratedBox(
              decoration: BoxDecoration(
                gradient: const LinearGradient(
                  colors: [Color(0xFF121620), Color(0xFF080A0F)],
                  begin: Alignment.topLeft,
                  end: Alignment.bottomRight,
                ),
                border: Border.all(color: Colors.white10, width: 1),
                borderRadius: BorderRadius.circular(24),
              ),
              child: Padding(
                padding: const EdgeInsets.all(12),
                child: DotMatrixWidget(
                  dotSize: _dotSize,
                  spacing: _spacing,
                  shape: _shape,
                  colorMode: _colorMode,
                  singleColor: _colorMode == DotColorMode.singleColor
                      ? _selectedSingleColor
                      : null,
                  stylePreset: _colorMode == DotColorMode.preset
                      ? _selectedPreset
                      : null,
                  blankColor: const Color(0xFF050608),
                  child: _buildPreviewChild(context),
                ),
              ),
            ),
          ),
        ),
      ],
    );
  }

  Widget _buildPreviewChild(BuildContext context) {
    final textTheme = Theme.of(context).textTheme;
    return Stack(
      fit: StackFit.expand,
      children: [
        Positioned.fill(
          child: Image.asset('assets/example.png', fit: BoxFit.cover),
        ),
        Positioned.fill(
          child: DecoratedBox(
            decoration: const BoxDecoration(
              gradient: LinearGradient(
                colors: [Color(0xCC0D2847), Color(0xCC09111C)],
                begin: Alignment.topLeft,
                end: Alignment.bottomRight,
              ),
            ),
          ),
        ),
        Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'DOT MATRIX',
                style: textTheme.displaySmall?.copyWith(
                  color: Colors.white,
                  fontWeight: FontWeight.w700,
                  letterSpacing: 8,
                ),
              ),
              const SizedBox(height: 12),
              Text(
                'Bring retro vibes to any widget. Experiment with LED shapes, colors, and classic display styles.',
                style: textTheme.bodyLarge?.copyWith(
                  color: Colors.white70,
                  height: 1.4,
                ),
              ),
              const SizedBox(height: 24),
              Wrap(
                spacing: 12,
                runSpacing: 12,
                children: const [
                  _DemoTag(label: 'Analog TV'),
                  _DemoTag(label: 'LED Panel'),
                  _DemoTag(label: 'Vintage Amber'),
                ],
              ),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildControls(BuildContext context) {
    final labelStyle = Theme.of(context).textTheme.titleMedium;
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('Controls', style: labelStyle),
        const SizedBox(height: 12),
        _ControlSection(
          children: [
            _buildDropdown<DotShapeType>(
              label: 'Dot shape',
              value: _shape,
              items: DotShapeType.values
                  .map(
                    (type) => DropdownMenuItem(
                      value: type,
                      child: Text(type.name.toUpperCase()),
                    ),
                  )
                  .toList(),
              onChanged: (value) {
                if (value != null) {
                  setState(() => _shape = value);
                }
              },
            ),
            _buildDropdown<DotColorMode>(
              label: 'Color mode',
              value: _colorMode,
              items: DotColorMode.values
                  .map(
                    (mode) => DropdownMenuItem(
                      value: mode,
                      child: Text(mode.name.toUpperCase()),
                    ),
                  )
                  .toList(),
              onChanged: (value) {
                if (value != null) {
                  setState(() => _colorMode = value);
                }
              },
            ),
            if (_colorMode == DotColorMode.singleColor)
              _buildDropdown<String>(
                label: 'Single color',
                value: _singleColorKey,
                items: _singleColorOptions.entries
                    .map(
                      (entry) => DropdownMenuItem(
                        value: entry.key,
                        child: Row(
                          children: [
                            Container(
                              width: 16,
                              height: 16,
                              margin: const EdgeInsets.only(right: 8),
                              decoration: BoxDecoration(
                                color: entry.value,
                                borderRadius: BorderRadius.circular(3),
                              ),
                            ),
                            Text(entry.key),
                          ],
                        ),
                      ),
                    )
                    .toList(),
                onChanged: (value) {
                  if (value != null) {
                    setState(() => _singleColorKey = value);
                  }
                },
              ),
            if (_colorMode == DotColorMode.preset)
              _buildDropdown<String>(
                label: 'Preset style',
                value: _presetKey,
                items: _presetFactories.keys
                    .map(
                      (key) => DropdownMenuItem(value: key, child: Text(key)),
                    )
                    .toList(),
                onChanged: (value) {
                  if (value != null) {
                    setState(() => _presetKey = value);
                  }
                },
              ),
          ],
        ),
        const SizedBox(height: 20),
        _ControlSection(
          children: [
            _buildSlider(
              context: context,
              label: 'Dot size',
              value: _dotSize,
              min: 2,
              max: 16,
              onChanged: (value) => setState(() => _dotSize = value),
            ),
            _buildSlider(
              context: context,
              label: 'Spacing',
              value: _spacing,
              min: 0,
              max: 6,
              onChanged: (value) => setState(() => _spacing = value),
            ),
          ],
        ),
      ],
    );
  }

  Widget _buildGallery(BuildContext context) {
    final labelStyle = Theme.of(context).textTheme.titleMedium;
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('Gallery', style: labelStyle),
        const SizedBox(height: 12),
        Wrap(
          spacing: 16,
          runSpacing: 16,
          children: [
            _buildGalleryCard(
              context,
              title: 'Reference Photo',
              child: Image.asset('assets/example.png', fit: BoxFit.cover),
            ),
            _buildGalleryCard(
              context,
              title: 'Flutter Logo',
              child: const Center(child: FlutterLogo(size: 96)),
            ),
            _buildGalleryCard(
              context,
              title: 'Music',
              child: const Center(
                child: Text('🎶', style: TextStyle(fontSize: 80)),
              ),
            ),
            _buildGalleryCard(
              context,
              title: 'Space Capsule',
              child: Center(
                child: Icon(
                  Icons.rocket_launch_rounded,
                  size: 72,
                  color: Colors.white,
                ),
              ),
            ),
            _buildGalleryCard(
              context,
              title: 'Typography',
              child: Center(
                child: Text(
                  'HELLO',
                  style: Theme.of(context).textTheme.displaySmall?.copyWith(
                    fontWeight: FontWeight.bold,
                    letterSpacing: 6,
                  ),
                ),
              ),
            ),
          ],
        ),
      ],
    );
  }

  Widget _buildGalleryCard(
    BuildContext context, {
    required String title,
    required Widget child,
  }) {
    return SizedBox(
      width: 160,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          ClipRRect(
            borderRadius: BorderRadius.circular(20),
            child: AspectRatio(
              aspectRatio: 1,
              child: DecoratedBox(
                decoration: BoxDecoration(
                  color: const Color(0xFF0A0C10),
                  border: Border.all(color: Colors.white12, width: 1),
                ),
                child: DotMatrixWidget(
                  dotSize: _dotSize,
                  spacing: _spacing,
                  shape: _shape,
                  colorMode: _colorMode,
                  singleColor: _colorMode == DotColorMode.singleColor
                      ? _selectedSingleColor
                      : null,
                  stylePreset: _colorMode == DotColorMode.preset
                      ? _selectedPreset
                      : null,
                  blankColor: const Color(0xFF050608),
                  child: Container(color: Colors.black, child: child),
                ),
              ),
            ),
          ),
          const SizedBox(height: 8),
          Text(title, style: Theme.of(context).textTheme.labelLarge),
        ],
      ),
    );
  }

  Widget _buildDropdown<T>({
    required String label,
    required T value,
    required List<DropdownMenuItem<T>> items,
    required ValueChanged<T?> onChanged,
  }) {
    return SizedBox(
      width: 220,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(label, style: Theme.of(context).textTheme.bodyMedium),
          const SizedBox(height: 8),
          DecoratedBox(
            decoration: BoxDecoration(
              color: const Color(0xFF12151C),
              borderRadius: BorderRadius.circular(12),
              border: Border.all(color: Colors.white10),
            ),
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 12),
              child: DropdownButton<T>(
                value: value,
                isExpanded: true,
                underline: const SizedBox.shrink(),
                dropdownColor: const Color(0xFF12151C),
                borderRadius: BorderRadius.circular(12),
                items: items,
                onChanged: onChanged,
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildSlider({
    required BuildContext context,
    required String label,
    required double value,
    required double min,
    required double max,
    required ValueChanged<double> onChanged,
  }) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(label, style: Theme.of(context).textTheme.bodyMedium),
            Text(
              value.toStringAsFixed(1),
              style: Theme.of(
                context,
              ).textTheme.bodySmall?.copyWith(color: Colors.white70),
            ),
          ],
        ),
        Slider(value: value, min: min, max: max, onChanged: onChanged),
      ],
    );
  }
}

class _DemoTag extends StatelessWidget {
  const _DemoTag({required this.label});

  final String label;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
      decoration: BoxDecoration(
        color: Colors.white.withValues(alpha: 0.08),
        borderRadius: BorderRadius.circular(999),
        border: Border.all(color: Colors.white12),
      ),
      child: Text(
        label,
        style: Theme.of(
          context,
        ).textTheme.labelLarge?.copyWith(color: Colors.white),
      ),
    );
  }
}

class _ControlSection extends StatelessWidget {
  const _ControlSection({required this.children});

  final List<Widget> children;

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: const Color(0xFF10131B),
        borderRadius: BorderRadius.circular(20),
        border: Border.all(color: Colors.white10),
      ),
      child: Wrap(spacing: 20, runSpacing: 20, children: children),
    );
  }
}
1
likes
160
points
203
downloads
screenshot

Publisher

unverified uploader

Weekly Downloads

Render any widget as a customizable dot-matrix display in Flutter.

Repository (GitHub)
View/report issues

Topics

#dot #widget #graphics #animation

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on dot_matrix_widget