flutterdartflutter-listviewflutter-sharedpreference

How to persist a List<String> toDo = ['eat', 'sleep', 'code'] using Flutter's SharedPreferences please?


I am making a Tasks app where users type in their tasks for the day and they can check off a task once complete. To Store tasks, i am starting with an empty [ ] that gets populated with user's input. How do i save that data using shared preferences package and display each list item in a Listview, Here's my code :

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tooodo/views/task_lists_containers.dart';

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

  @override
  State<TasksScreen> createState() => _TasksScreenState();
}

class _TasksScreenState extends State<TasksScreen> {
  // hard-coded a list of words. How do i get our to-do items from a database.
  // the database will contain all user input.
  List<String> toDoItems = [
    'play',
    'eat',
  ];

  final TextEditingController _taskTextFieldController = TextEditingController();

 

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: const Color.fromARGB(255, 7, 152, 70),
        title: const Text('Tasks'),
        centerTitle: true,
      ),
      body: Container(
          padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
          // ignore: prefer_const_literals_to_create_immutables
          child: ListView.builder(
              itemCount: toDoItems.length,
              itemBuilder: (context, index) {

                return TaskContainer(
                  child: toDoItems[index],
                );
              })),

      // floating action bar and onpressed function
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          showDialog(
            context: context,
            builder: (BuildContext context) {
              // return object of type Scaffold
              return AlertDialog(
                shape: const RoundedRectangleBorder(
                    borderRadius: BorderRadius.all(Radius.circular(15))),
                content: TextField(
                  controller: _taskTextFieldController,
                  textInputAction: TextInputAction.done,
                  decoration: InputDecoration(hintText: 'Task'),
                ),
                actions: <Widget>[
                  TextButton(
                    child: Text("Save"),
                    onPressed: () {
                      toDoItems.add(_taskTextFieldController.text);
                      Navigator.of(context).pop();
                      _taskTextFieldController.clear();
                      setState(() {});
                    },
                  ),
                ],
              );
            },
          );
        },
        enableFeedback: true,
        child: const Icon(Icons.add),
      ),
    );
  }
}

I welcome any advise pertaining to the code in terms of cleanliness and common standards am not following.


Solution

  • I created two functions:

    To load from shared preferences:

    List<String>? _toDoList;
    
      Future<void> _loadToDoItems() async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
        setState(() {
          _toDoList = prefs.getStringList('toDoList') ?? [];
        });
      }
    

    And to save to shared preferences:

    _saveToDoItems() async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
        prefs.setStringList('toDoList', _toDoList != null ? _toDoList! : []);
      }
    

    We call _loadToDoItems() in initState and _saveToDoItems() within the TextButton():

     TextButton(
                        child: Text("Save"),
                        onPressed: () {
                          // add the task to the list and save to shared preferences
                          setState(() {
                            _toDoList?.add(_taskTextFieldController.text);
                            _taskTextFieldController.clear();
                            _saveToDoItems();
                          });
    
                          Navigator.of(context).pop();
                          _taskTextFieldController.clear();
                          setState(() {});
                        },
                      ),
    

    Here is a complete runnable example (note: You'll have to fully stop your current project before using this snippet):

    import 'package:flutter/material.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData.dark().copyWith(
            scaffoldBackgroundColor: darkBlue,
          ),
          debugShowCheckedModeBanner: false,
          home: Scaffold(
            body: Center(
              child: TasksScreen(),
            ),
          ),
        );
      }
    }
    
    class TasksScreen extends StatefulWidget {
      const TasksScreen({Key? key}) : super(key: key);
    
      @override
      State<TasksScreen> createState() => _TasksScreenState();
    }
    
    class _TasksScreenState extends State<TasksScreen> {
      
      List<String>? _toDoList;
      Future<void> _loadToDoItems() async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
        setState(() {
          _toDoList = prefs.getStringList('toDoList') ?? [];
        });
      }
    
      _saveToDoItems() async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
        prefs.setStringList('toDoList', _toDoList != null ? _toDoList! : []);
      }
    
      final TextEditingController _taskTextFieldController =
          TextEditingController();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            backgroundColor: const Color.fromARGB(255, 7, 152, 70),
            title: const Text('Tasks'),
            centerTitle: true,
          ),
          body: Container(
              padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
              // ignore: prefer_const_literals_to_create_immutables
              child: ListView.builder(
                  itemCount: _toDoList?.length,
                  itemBuilder: (context, index) {
                    return Container(
                      child: Text(_toDoList![index]),
                    );
                  })),
    
          // floating action bar and onpressed function
          floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              showDialog(
                context: context,
                builder: (BuildContext context) {
                  // return object of type Scaffold
                  return AlertDialog(
                    shape: const RoundedRectangleBorder(
                        borderRadius: BorderRadius.all(Radius.circular(15))),
                    content: TextField(
                      controller: _taskTextFieldController,
                      textInputAction: TextInputAction.done,
                      decoration: InputDecoration(hintText: 'Task'),
                    ),
                    actions: <Widget>[
                      TextButton(
                        child: Text("Save"),
                        onPressed: () {
                          // add the task to the list and save to shared preferences
                          setState(() {
                            _toDoList?.add(_taskTextFieldController.text);
                            _taskTextFieldController.clear();
                            _saveToDoItems();
                          });
    
                          Navigator.of(context).pop();
                          _taskTextFieldController.clear();
                          setState(() {});
                        },
                      ),
                    ],
                  );
                },
              );
            },
            enableFeedback: true,
            child: const Icon(Icons.add),
          ),
        );
      }
    
    //  load list from shared preferences
      @override
      void initState() {
        _loadToDoItems();
    
        super.initState();
      }
    }
    
    

    Result:

    enter image description here