declarative_animated_list 0.2.0 copy "declarative_animated_list: ^0.2.0" to clipboard
declarative_animated_list: ^0.2.0 copied to clipboard

An implementation of animated list widget that will be automatically updated based on different lists snippets.

example/lib/main.dart

import 'package:declarative_animated_list/declarative_animated_list.dart';
import 'package:example/bloc.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    final ToDosBloc bloc = ToDosBloc();
    return MaterialApp(
      title: 'Declarative Animated List Demo',
      theme: ThemeData.dark(),
      home: ToDosPage(
        bloc: bloc,
      ),
    );
  }
}

class ToDosPage extends StatelessWidget {
  final ToDosBloc bloc;

  const ToDosPage({required this.bloc, super.key});

  @override
  Widget build(final BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: StreamBuilder<ToDosState>(
        stream: bloc.toDosState,
        builder: (_, final AsyncSnapshot<ToDosState> snapshot) {
          return _buildBody(context, snapshot);
        },
      ),
      floatingActionButton: _buildFab(context),
    );
  }

  Widget _buildBody(
    BuildContext context,
    AsyncSnapshot<ToDosState> snapshot,
  ) {
    if (snapshot.hasData) {
      return _buildBasedOnState(context, snapshot.data!);
    } else if (snapshot.hasError) {
      return Center(
        child: Text(
          'Error occurred: ${snapshot.error}',
          textAlign: TextAlign.center,
          style: const TextStyle(color: Colors.black),
        ),
      );
    } else {
      return const Center(child: CircularProgressIndicator());
    }
  }

  Widget _buildBasedOnState(
    BuildContext context,
    ToDosState state,
  ) {
    final List<ToDoPresentationModel> toDos = state.toDos.toList()
      ..sort(
        (left, right) {
          if (left.isCompleted == right.isCompleted) {
            return left.description.compareTo(right.description);
          } else {
            return left.isCompleted ? 1 : -1;
          }
        },
      );
    if (toDos.isEmpty) {
      return Center(
        child: Icon(
          Icons.delete_outline,
          size: MediaQuery.of(context).size.height * 0.4,
          color: Theme.of(context).colorScheme.secondary,
        ),
      );
    } else {
      return DeclarativeList<ToDoPresentationModel>(
        items: toDos,
        insertDuration: const Duration(milliseconds: 500),
        removeDuration: const Duration(milliseconds: 500),
        itemBuilder: (_, model, __, anim) =>
            _buildFadeAndSizeTransitioningTile(anim, model),
        removeBuilder: (_, model, __, anim) =>
            _buildFadeAndSizeTransitioningTile(anim, model),
      );
    }
  }

  Widget _buildFadeAndSizeTransitioningTile(
    Animation<double> animation,
    ToDoPresentationModel model,
  ) {
    return FadeTransition(
      opacity: animation,
      child: SizeTransition(sizeFactor: animation, child: _buildTile(model)),
    );
  }

  Widget _buildTile(ToDoPresentationModel toDo) {
    return ListTile(
      onLongPress: () => bloc.removeToDo.add(RemoveToDoEvent(toDo)),
      title: Text(toDo.description),
      leading: IconButton(
        icon: Icon(toDo.isCompleted ? Icons.check : Icons.sync),
        onPressed: () {
          bloc.changeToDoStatus.add(
            ChangeCompletionStatusEvent(
              toDo,
              shouldBeCompleted: !toDo.isCompleted,
            ),
          );
        },
      ),
    );
  }

  Widget _buildFab(BuildContext context) {
    return FloatingActionButton(
      child: const Icon(Icons.add),
      onPressed: () => showDialog<void>(
        context: context,
        builder: (ctx) {
          final controller = TextEditingController();
          final size = MediaQuery.sizeOf(ctx);
          return Container(
            height: size.height * 0.5,
            width: size.width * 0.5,
            padding: const EdgeInsets.all(16.0),
            child: Material(
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: TextField(controller: controller),
                  ),
                  IconButton(
                    icon: const Icon(Icons.check),
                    onPressed: () {
                      bloc.addToDo.add(AddToDoEvent(controller.text));
                      Navigator.of(ctx).pop();
                    },
                  )
                ],
              ),
            ),
          );
        },
      ),
    );
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty('bloc', bloc));
  }
}
20
likes
120
pub points
74%
popularity

Publisher

unverified uploader

An implementation of animated list widget that will be automatically updated based on different lists snippets.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (LICENSE)

Dependencies

flutter

More

Packages that depend on declarative_animated_list