leulit_flutter_actionmanager 4.6.0 copy "leulit_flutter_actionmanager: ^4.6.0" to clipboard
leulit_flutter_actionmanager: ^4.6.0 copied to clipboard

A lightweight, type-safe action dispatcher for Flutter applications. Works seamlessly across all layers - UI, domain, data, and services.

example/lib/main.dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:leulit_flutter_actionmanager/leulit_flutter_actionmanager.dart';

void main() {
  // Configurar logger (opcional)
  ActionManager.configureLogger(
    enabled: true,
    showTimestamp: true,
  );

  runApp(const MyApp());
}

/// Enum de acciones de ejemplo
enum AppAction {
  increment,
  decrement,
  reset,
  randomNumber,
  loadData, // Nueva acción para demostrar loading
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Action Dispatcher Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const HomePage(),
    );
  }
}

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _counter = 0;
  final _subscriptions = <StreamSubscription>[];

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

    // ✅ Pattern correcto: usar listen() con cleanup
    _subscriptions.add(
      ActionManager.listen(AppAction.increment, (_) {
        if (mounted) setState(() => _counter++);
      }),
    );

    _subscriptions.add(
      ActionManager.listen(AppAction.decrement, (_) {
        if (mounted) setState(() => _counter--);
      }),
    );

    _subscriptions.add(
      ActionManager.listen(AppAction.reset, (_) {
        if (mounted) setState(() => _counter = 0);
      }),
    );

    _subscriptions.add(
      ActionManager.listen<int>(AppAction.randomNumber, (number) {
        if (mounted && number != null) {
          setState(() => _counter = number);
        }
      }),
    );

    // Handler para simular carga de datos
    _subscriptions.add(
      ActionManager.listen(AppAction.loadData, (_) {
        // Simular operación costosa
        Future.delayed(const Duration(seconds: 2), () {
          if (mounted) setState(() => _counter = 42);
        });
      }),
    );
  }

  @override
  void dispose() {
    // ✅ CRÍTICO: Cancelar todas las subscriptions para prevenir memory leaks
    for (final subscription in _subscriptions) {
      subscription.cancel();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Action Dispatcher Demo'),
        actions: [
          IconButton(
            icon: const Icon(Icons.info_outline),
            onPressed: () {
              // Mostrar estadísticas
              ActionManager.printSummary();

              // También en UI
              showDialog(
                context: context,
                builder: (context) => const StatsDialog(),
              );
            },
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('Counter Value:', style: TextStyle(fontSize: 20)),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.displayLarge,
            ),
            const SizedBox(height: 40),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton.icon(
                  icon: const Icon(Icons.remove),
                  label: const Text('Decrement'),
                  onPressed: () {
                    ActionManager.dispatch(AppAction.decrement);
                  },
                ),
                const SizedBox(width: 10),
                ElevatedButton.icon(
                  icon: const Icon(Icons.add),
                  label: const Text('Increment'),
                  onPressed: () {
                    ActionManager.dispatch(AppAction.increment);
                  },
                ),
              ],
            ),
            const SizedBox(height: 20),
            ElevatedButton.icon(
              icon: const Icon(Icons.refresh),
              label: const Text('Reset'),
              onPressed: () {
                ActionManager.dispatch(AppAction.reset);
              },
            ),
            const SizedBox(height: 20),
            ElevatedButton.icon(
              icon: const Icon(Icons.shuffle),
              label: const Text('Random Number'),
              onPressed: () {
                final random = DateTime.now().millisecond;
                ActionManager.dispatch(AppAction.randomNumber, data: random);
              },
            ),
            const SizedBox(height: 40),
            const SecondWidget(),
          ],
        ),
      ),
    );
  }
}

/// Widget adicional que también escucha las mismas acciones
class SecondWidget extends StatefulWidget {
  const SecondWidget({super.key});

  @override
  State<SecondWidget> createState() => _SecondWidgetState();
}

class _SecondWidgetState extends State<SecondWidget> {
  int _localCounter = 0;
  final _subscriptions = <StreamSubscription>[];

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

    // Este widget también responde a las acciones
    _subscriptions.add(
      ActionManager.listen(AppAction.increment, (_) {
        if (mounted) setState(() => _localCounter++);
      }),
    );

    _subscriptions.add(
      ActionManager.listen(AppAction.reset, (_) {
        if (mounted) setState(() => _localCounter = 0);
      }),
    );
  }

  @override
  void dispose() {
    for (final subscription in _subscriptions) {
      subscription.cancel();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(16),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            const Text(
              'This widget also listens to actions!',
              style: TextStyle(fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            Text('Local counter: $_localCounter'),
          ],
        ),
      ),
    );
  }
}

/// Dialog que muestra estadísticas
class StatsDialog extends StatelessWidget {
  const StatsDialog({super.key});

  @override
  Widget build(BuildContext context) {
    final stats = ActionManager.getStats();

    return AlertDialog(
      title: const Text('📊 Dispatcher Stats'),
      content: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('Total Actions: ${stats.totalActions}'),
          Text('Total Handlers: ${stats.totalHandlers}'),
          Text('Total Dispatches: ${stats.totalDispatches}'),
          const SizedBox(height: 16),
          const Text('Action Details:',
              style: TextStyle(fontWeight: FontWeight.bold)),
          ...AppAction.values.map((action) {
            final metadata = ActionManager.getMetadata(action);
            return Padding(
              padding: const EdgeInsets.only(top: 8),
              child: Text(
                '${action.name}: ${metadata.handlerCount} handlers, '
                '${metadata.dispatchCount} dispatches',
                style: const TextStyle(fontSize: 12),
              ),
            );
          }),
        ],
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('Close'),
        ),
      ],
    );
  }
}
0
likes
0
points
702
downloads

Publisher

unverified uploader

Weekly Downloads

A lightweight, type-safe action dispatcher for Flutter applications. Works seamlessly across all layers - UI, domain, data, and services.

Repository (GitHub)
View/report issues

Topics

#state-management #architecture #events #actions #dispatcher

License

unknown (license)

Dependencies

flutter, meta

More

Packages that depend on leulit_flutter_actionmanager