'How can I update a filtered list in Flutter?

I am developing a todo app in Flutter.

I'm currently trying to delete all completed todos, but somehow I couldn't update the completed part in my main list. I am using Provider as state management.

  • What I want to do: When I click the Clear Todos button, delete all the completed todos in my todos list. I don't want to delete all the todos. I just want to clear all "completed" todos.

TodosProvider codes

import 'dart:collection';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:todo_app/Models/todo.dart';

class TodosProvider extends ChangeNotifier {
  SharedPreferences? sharedPreferences;

  //initial state
  List<Todo> todos = [];

  //  getter
  UnmodifiableListView<Todo> get allTodos =>
      UnmodifiableListView(todos.reversed);

  UnmodifiableListView<Todo> get completedTodos =>
      UnmodifiableListView(todos.reversed.where((todo) => todo.complete));

  UnmodifiableListView<Todo> get unCompletedTodos =>
      UnmodifiableListView(todos.reversed.where((todo) => !todo.complete));

//  methods for Todo
  void addTodo(Todo todo) {
    todos.add(todo);
    saveDataToLocalStorage();
    notifyListeners();
  }

  void removeTodo(Todo todo) {
    todos.remove(todo);
    updateDataToLocalStorage();
    checkCompletedTodos();
    notifyListeners();
  }

  bool checkCompletedTodos() {
    if (completedTodos.isEmpty) {
      notifyListeners();
      return true;
    }
    notifyListeners();
    return false;
  }

  void removeCompletedTodos() {
    List<Todo> compTodos = (todos.where((todo) => todo.complete).toList());
    print('length before delete : ${compTodos.length}');
    compTodos.clear();
    todos.where((todo) => todo.complete) == compTodos;
    print('length after clear: ${compTodos.length}');
    todos.addAll(compTodos);
    updateDataToLocalStorage();
    print('List deleted');
    notifyListeners();

  }

  void toggleTodo(Todo todo) {
    var index = todos.indexOf(todo);
    todos[index].toggleCompleted();
    updateDataToLocalStorage();
    notifyListeners();
  }

  // methods for shared preferences
  void initSharedPreferences() async {
    sharedPreferences = await SharedPreferences.getInstance();
    loadDataFromLocalStorage();
    notifyListeners();
  }

  // Percent Method
  double calcTodoPercent() {
    double percent = (completedTodos.length / allTodos.length);
    print('Percent : $percent');
    print('Comp todos : ${completedTodos.length}');
    print('UnComp todos : ${unCompletedTodos.length}');
    print(percent.runtimeType);
    return (completedTodos == 0 && unCompletedTodos == 0) ? 0 : percent;
  }

  void saveDataToLocalStorage() {
    List<String>? spList =
        todos.map((todo) => json.encode(todo.toJson())).toList();
    sharedPreferences!.setStringList('list', spList);
  }

  void loadDataFromLocalStorage() {
    List<String>? spList = sharedPreferences!.getStringList('list');
    todos = spList!.map((item) => Todo.fromMap(json.decode(item))).toList();
  }

  void updateDataToLocalStorage() {
    List<String>? spList =
        todos.map((item) => json.encode(item.toJson())).toList();
    sharedPreferences?.remove('list');
    sharedPreferences!.setStringList('list', spList);
  }
}

Dashboard Page button codes:

import 'package:flutter/material.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:todo_app/Widgets/Dashboard/complete_todo_list.dart';
import 'package:todo_app/Widgets/Dashboard/completed_task_info.dart';

class DashboardPage extends StatefulWidget {
  const DashboardPage({Key? key}) : super(key: key);

  @override
  _DashboardPageState createState() => _DashboardPageState();
}

class _DashboardPageState extends State<DashboardPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: DashboardAP(),
      body: Container(
        color: HexColor('#f9f6e8'),
        child: Column(
          children: const [
            CompletedTaskInfo(),
            CompleteTodoList()
          ],
        ),
      ),
    );
  }
}

AppBar DashboardAP() {
  return AppBar(
    leading: const Padding(
        padding: EdgeInsets.only(left: 10.0, top: 15.0),
        child: Icon(Icons.settings, color: Colors.black)),
    //Icon(Icons.settings),
    backgroundColor: HexColor('#f9f6e8'),
    elevation: 0,
  );
}

completed_task_ifo widget codes :

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:todo_app/provider/todos_provider.dart';

class CompletedTaskInfo extends StatefulWidget {
  const CompletedTaskInfo({Key? key}) : super(key: key);

  @override
  _Task_InfoState createState() => _Task_InfoState();
}

class _Task_InfoState extends State<CompletedTaskInfo> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 24.0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Padding(
            padding: const EdgeInsets.only(top: 10.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text(
                  'Your tasks',
                  style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                ),
                Padding(
                    padding: const EdgeInsets.only(top: 8.0),
                    child: Consumer<TodosProvider>(
                      builder: (context, state, child) => Text(
                        'You have ${state.completedTodos.length} tasks completed all time',
                        style: const TextStyle(
                            fontSize: 15,
                            fontWeight: FontWeight.bold,
                            color: Colors.grey),
                      ),
                    ))
              ],
            ),
          ),
          ElevatedButton(onPressed:
          () {
            Provider.of<TodosProvider>(context,listen: false).checkCompletedTodos() ? print('Şuan da liste boş')
                : Provider.of<TodosProvider>(context,listen: false).removeCompletedTodos();
          }

            , child: const Text('Clear Todos',style: TextStyle(fontSize: 10),),
            style: ElevatedButton.styleFrom(shape: StadiumBorder()),
          )
        ],
      ),
    );
  }
}

completed todo list widget codes:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:todo_app/Models/todo.dart';
import 'package:todo_app/Pages/detail_screen.dart';
import 'package:todo_app/Widgets/Todo/todo_card.dart';
import 'package:todo_app/provider/todos_provider.dart';

import 'complete_todo_card.dart';

class CompleteTodoList extends StatefulWidget {
  const CompleteTodoList({Key? key}) : super(key: key);

  @override
  _CompleteTodoListState createState() => _CompleteTodoListState();
}

class _CompleteTodoListState extends State<CompleteTodoList> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(top: 20.0),
      child: Consumer<TodosProvider>(
        builder: (context, state, child) => SizedBox(
          height: MediaQuery.of(context).size.height / 1.48,
          child: ListView.builder(
              itemCount: state.completedTodos.length,
              itemBuilder: (context, index) {
                return CompleteTodoCard(
                  todo: state.completedTodos[index],
                );
              }),
        ),
      ),
    );
  }
}

Technically I did this but nothing changes as I can't update my master list.

I've been researching this all day but haven't been able to find anything and solve it. I would be very happy if you help.



Solution 1:[1]

No one answered but I just solved it. I was able to delete the completed todos in my list with the method below.

  void removeCompletedTodos() {
    todos.forEach((todo) {
      if (todo.complete) {
        var index = todos.indexOf(todo);
        completedTodosList.add(todo);
        notifyListeners();
      }
    });
    todos.removeWhere((todo) => completedTodosList.contains(todo));
    updateDataToLocalStorage();
    notifyListeners();
  }

My other codes are the same, I just created a new list to mark the completeds.

List<Todo> completedTodosList = [];

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Y?lmaz Ya??z Dokumac?