Search code examples
flutterblocclean-architecturestate-managementflutter-bloc

flutter bloc: how can i access to variables in bloc all over of tree?


I want to access one or more lists or variables throughout the tree of my program and also perform operations of adding, deleting, editing on that list, I solve this problem by using the provider package as below figure:

I in first make this class

class TaskData extends ChangeNotifier {
  List<Task> _tasks = [
    Task(title: 'Buy Milk'),
    Task(title: 'Buy Eggs'),
    Task(title: 'Buy Bread'),
  ];

  UnmodifiableListView<Task> get tasks => UnmodifiableListView(_tasks);

  int get taskCount => _tasks.length;

  toggleDone(index) {
    _tasks[index].toggleDone();
    notifyListeners();
  }

  addTask(data) {
    _tasks.add(Task(title: data));
  }

  removeTask(index) {
    _tasks.removeAt(index);
    notifyListeners();
  }
}

Then provide tree like this

void main() {
  runApp(ChangeNotifierProvider(
    create: (BuildContext context) => TaskData(),
    child: MaterialApp(
      theme: ThemeData(
        useMaterial3: true,
      ),
      home: TasksScreen(),
    ),
  ));
}

And i use like this code

class TasksList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<TaskData>(
      builder: (context, taskData, child) {
        return ListView.builder(
          itemCount: taskData.taskCount,
          itemBuilder: (context, index) {
            print(taskData.tasks[index]);
            return TaskTile(
              taskTitle: taskData.tasks[index].title,
              isChecked: taskData.tasks[index].isDone,
              checkboxCallback: (newValue) {
                taskData.toggleDone(index);
              },
              listTileCallback: () {
                taskData.removeTask(index);
              },
            );
          },
        );
      },
    );
  }
}

Now, I need to learn how to do this with the bloc and flutter_bloc and clean architecture that such as model class and entity class and repository class and all clean architecture system?


Solution

    1. Think about the events can happen [Event class]
    2. How many states can be [State class]
    3. Handle logic on Bloc [Main Bloc]
    class Task extends Equatable { //import 'package:equatable/equatable.dart';
      const Task({
        required this.title,
        this.isDone = false,
      });
      final String title;
      final bool isDone;
    
      @override
      List<Object?> get props => [title, isDone];
    
      Task copyWith({
        String? title,
        bool? isDone,
      }) {
        return Task(
          title: title ?? this.title,
          isDone: isDone ?? this.isDone,
        );
      }
    }
    
    abstract class TaskEvent extends Equatable {
      const TaskEvent();
    
      @override
      List<Object> get props => [];
    }
    
    class ToggleDone extends TaskEvent {
      const ToggleDone(this.task);
      final Task task;
    
      @override
      List<Object> get props => [task];
    }
    
    class AddTask extends TaskEvent {
      const AddTask(this.task);
      final Task task;
    
      @override
      List<Object> get props => [task];
    }
    
    class RemoveTask extends TaskEvent {
      const RemoveTask(this.task);
      final Task task;
    
      @override
      List<Object> get props => [task];
    }
    
    ///state
    class TaskState extends Equatable {
      const TaskState(this.tasks);
    
      final List<Task> tasks;
      @override
      List<Object> get props => [tasks, identityHashCode(this)];
    }
    
    //bloc
    
    class TaskBloc extends Bloc<TaskEvent, TaskState> {
      TaskBloc([List<Task> tasks = const []]) : super(TaskState(tasks)) {
        on<ToggleDone>((event, emit) {
          final item = event.task;
          final tasks = state.tasks;
          final index = tasks.indexWhere((element) => element == item);
    
          tasks[index] = item.copyWith(isDone: !item.isDone);
          emit(TaskState([...tasks]));
        });
    
        on<AddTask>(
          (event, emit) {
            final tasks = state.tasks;
            tasks.add(event.task);
            emit(TaskState([...tasks]));
          },
        );
    
        on<RemoveTask>((event, emit) {
          final tasks = state.tasks;
          tasks.remove(event.task);
          emit(TaskState([...tasks]));
        });
      }
    }
    

    And Main file

    import 'package:flutter/material.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    import 'package:equatable/equatable.dart';
    
    const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
    
          List<Task> _tasks = [
        Task(title: 'Buy Milk'),
        Task(title: 'Buy Eggs'),
        Task(title: 'Buy Bread'),
      ];
      @override
      Widget build(BuildContext context) {
        return MultiBlocProvider(
          providers: [
            BlocProvider(create: (context) => TaskBloc(_tasks)),
          ],
          child: MaterialApp(
            home: Scaffold(
              body: TasksList(),
            ),
          ),
        );
      }
    }
    
    class TasksList extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
    
        return BlocBuilder<TaskBloc, TaskState>(
          builder: (context, taskData) {
            return ListView.builder(
              itemCount: taskData.tasks.length,
              itemBuilder: (context, index) {
                print(taskData.tasks[index]);
                return ListTile(
                  title: Text(taskData.tasks[index].title),
                  leading: Checkbox(
                      value: taskData.tasks[index].isDone,
                      onChanged: (value) {
                        context
                            .read<TaskBloc>()
                            .add(ToggleDone(taskData.tasks[index]));
                      }),
                  trailing: IconButton(
                      onPressed: () {
                        context
                            .read<TaskBloc>()
                            .add(RemoveTask(taskData.tasks[index]));
                      },
                      icon: Icon(Icons.delete)),
                );
              },
            );
          },
        );
      }
    }
    

    You can follow bloclibrary and their example code .