collection_notifiers 2.0.1 copy "collection_notifiers: ^2.0.1" to clipboard
collection_notifiers: ^2.0.1 copied to clipboard

Reactive collection wrappers (List, Map, Set, Queue) with ChangeNotifier and ValueListenable support for efficient Flutter UI rebuilds.

example/lib/main.dart

import 'dart:collection';

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Collection Notifiers Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 4,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Collection Notifiers'),
          bottom: const TabBar(
            tabs: [
              Tab(text: 'List'),
              Tab(text: 'Set'),
              Tab(text: 'Map'),
              Tab(text: 'Queue'),
            ],
          ),
        ),
        body: const TabBarView(
          children: [
            ListExample(),
            SetExample(),
            MapExample(),
            QueueExample(),
          ],
        ),
      ),
    );
  }
}

// -----------------------------------------------------------------------------
// ListNotifier Example
// -----------------------------------------------------------------------------

final _listNotifier = ListNotifier<String>(['Apple', 'Banana', 'Cherry']);

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

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<List<String>>(
      valueListenable: _listNotifier,
      builder: (context, items, child) {
        return Column(
          children: [
            Padding(
              padding: const EdgeInsets.all(16),
              child: Row(
                children: [
                  Expanded(
                    child: ElevatedButton.icon(
                      onPressed: () =>
                          _listNotifier.add('Item ${items.length + 1}'),
                      icon: const Icon(Icons.add),
                      label: const Text('Add'),
                    ),
                  ),
                  const SizedBox(width: 8),
                  Expanded(
                    child: ElevatedButton.icon(
                      onPressed:
                          items.isEmpty ? null : _listNotifier.removeLast,
                      icon: const Icon(Icons.remove),
                      label: const Text('Remove'),
                    ),
                  ),
                  const SizedBox(width: 8),
                  Expanded(
                    child: ElevatedButton.icon(
                      onPressed:
                          items.length > 1 ? _listNotifier.shuffle : null,
                      icon: const Icon(Icons.shuffle),
                      label: const Text('Shuffle'),
                    ),
                  ),
                ],
              ),
            ),
            Expanded(
              child: ReorderableListView.builder(
                itemCount: items.length,
                onReorder: (oldIndex, newIndex) {
                  if (newIndex > oldIndex) newIndex--;
                  final item = _listNotifier.removeAt(oldIndex);
                  _listNotifier.insert(newIndex, item);
                },
                itemBuilder: (context, index) {
                  return ListTile(
                    key: ValueKey('$index-${items[index]}'),
                    leading: CircleAvatar(child: Text('${index + 1}')),
                    title: Text(items[index]),
                    trailing: IconButton(
                      icon: const Icon(Icons.delete),
                      onPressed: () => _listNotifier.removeAt(index),
                    ),
                  );
                },
              ),
            ),
          ],
        );
      },
    );
  }
}

// -----------------------------------------------------------------------------
// SetNotifier Example
// -----------------------------------------------------------------------------

final _setNotifier = SetNotifier<int>();

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

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<Set<int>>(
      valueListenable: _setNotifier,
      builder: (context, selectedIds, child) {
        return Column(
          children: [
            Padding(
              padding: const EdgeInsets.all(16),
              child: Text(
                'Selected: ${selectedIds.length} items',
                style: Theme.of(context).textTheme.titleMedium,
              ),
            ),
            Expanded(
              child: ListView.builder(
                itemCount: 20,
                itemBuilder: (context, index) {
                  final isSelected = selectedIds.contains(index);
                  return CheckboxListTile(
                    value: isSelected,
                    title: Text('Item $index'),
                    subtitle: Text(isSelected ? 'Selected' : 'Tap to select'),
                    onChanged: (_) => _setNotifier.invert(index),
                  );
                },
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(16),
              child: ElevatedButton(
                onPressed: selectedIds.isEmpty ? null : _setNotifier.clear,
                child: const Text('Clear Selection'),
              ),
            ),
          ],
        );
      },
    );
  }
}

// -----------------------------------------------------------------------------
// MapNotifier Example
// -----------------------------------------------------------------------------

final _mapNotifier = MapNotifier<String, int>({
  'Apples': 5,
  'Oranges': 3,
  'Bananas': 7,
});

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

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<Map<String, int>>(
      valueListenable: _mapNotifier,
      builder: (context, cart, child) {
        final total = cart.values.fold<int>(0, (sum, qty) => sum + qty);
        return Column(
          children: [
            Padding(
              padding: const EdgeInsets.all(16),
              child: Text(
                'Total items: $total',
                style: Theme.of(context).textTheme.titleMedium,
              ),
            ),
            Expanded(
              child: ListView(
                children: cart.entries.map((entry) {
                  return ListTile(
                    title: Text(entry.key),
                    subtitle: Text('Quantity: ${entry.value}'),
                    trailing: Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        IconButton(
                          icon: const Icon(Icons.remove_circle_outline),
                          onPressed: entry.value > 0
                              ? () => _mapNotifier[entry.key] = entry.value - 1
                              : null,
                        ),
                        Text('${entry.value}'),
                        IconButton(
                          icon: const Icon(Icons.add_circle_outline),
                          onPressed: () =>
                              _mapNotifier[entry.key] = entry.value + 1,
                        ),
                        IconButton(
                          icon: const Icon(Icons.delete),
                          onPressed: () => _mapNotifier.remove(entry.key),
                        ),
                      ],
                    ),
                  );
                }).toList(),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(16),
              child: ElevatedButton.icon(
                onPressed: () {
                  final name = 'Item ${cart.length + 1}';
                  _mapNotifier[name] = 1;
                },
                icon: const Icon(Icons.add),
                label: const Text('Add Item'),
              ),
            ),
          ],
        );
      },
    );
  }
}

// -----------------------------------------------------------------------------
// QueueNotifier Example
// -----------------------------------------------------------------------------

final _queueNotifier = QueueNotifier<String>();

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

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<Queue<String>>(
      valueListenable: _queueNotifier,
      builder: (context, queue, child) {
        return Column(
          children: [
            Padding(
              padding: const EdgeInsets.all(16),
              child: Row(
                children: [
                  Expanded(
                    child: ElevatedButton.icon(
                      onPressed: () => _queueNotifier
                          .addFirst('First ${DateTime.now().second}'),
                      icon: const Icon(Icons.first_page),
                      label: const Text('Add First'),
                    ),
                  ),
                  const SizedBox(width: 8),
                  Expanded(
                    child: ElevatedButton.icon(
                      onPressed: () => _queueNotifier
                          .addLast('Last ${DateTime.now().second}'),
                      icon: const Icon(Icons.last_page),
                      label: const Text('Add Last'),
                    ),
                  ),
                ],
              ),
            ),
            Expanded(
              child: queue.isEmpty
                  ? const Center(child: Text('Queue is empty'))
                  : ListView.builder(
                      itemCount: queue.length,
                      itemBuilder: (context, index) {
                        final item = queue.elementAt(index);
                        return ListTile(
                          leading: CircleAvatar(child: Text('${index + 1}')),
                          title: Text(item),
                          trailing: index == 0
                              ? const Chip(label: Text('HEAD'))
                              : index == queue.length - 1
                                  ? const Chip(label: Text('TAIL'))
                                  : null,
                        );
                      },
                    ),
            ),
            Padding(
              padding: const EdgeInsets.all(16),
              child: Row(
                children: [
                  Expanded(
                    child: ElevatedButton.icon(
                      onPressed:
                          queue.isEmpty ? null : _queueNotifier.removeFirst,
                      icon: const Icon(Icons.remove),
                      label: const Text('Remove First'),
                    ),
                  ),
                  const SizedBox(width: 8),
                  Expanded(
                    child: ElevatedButton.icon(
                      onPressed:
                          queue.isEmpty ? null : _queueNotifier.removeLast,
                      icon: const Icon(Icons.remove),
                      label: const Text('Remove Last'),
                    ),
                  ),
                ],
              ),
            ),
          ],
        );
      },
    );
  }
}
6
likes
160
points
268
downloads

Publisher

verified publishermehmetesen.com

Weekly Downloads

Reactive collection wrappers (List, Map, Set, Queue) with ChangeNotifier and ValueListenable support for efficient Flutter UI rebuilds.

Homepage
Repository (GitHub)
View/report issues

Topics

#state-management #flutter #collections #change-notifier #value-listenable

Documentation

API reference

License

MIT (license)

Dependencies

collection, flutter

More

Packages that depend on collection_notifiers