Home > Mobile >  How to persist a List<String> toDo = ['eat', 'sleep', 'code'] us
How to persist a List<String> toDo = ['eat', 'sleep', 'code'] us

Time:07-08

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.

CodePudding user response:

You can follow this snippet, I am using getStringList and setStringList.

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

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

class _TasksScreenState extends State<TasksScreen> {

  final TextEditingController _taskTextFieldController =
      TextEditingController();

  static const String listKey = "ITEMS";

  Future<List<String>?> getItems() async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getStringList(listKey) ?? [];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: const Color.fromARGB(255, 7, 152, 70),
        title: const Text('Tasks'),
        centerTitle: true,
      ),
      body: FutureBuilder<List<String>?>(
          future: getItems(),
          builder: (context, snapshot) {
            return ListView.builder(
              itemCount: snapshot.data?.length,
              itemBuilder: (context, index) {
                return Text(snapshot.data![index]);
              },
            );
          }),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          await 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: () async {
                      final prefs = await SharedPreferences.getInstance();
                      final oldItems = prefs.getStringList(listKey) ?? [];
                      await prefs.setStringList(listKey,
                          [...oldItems, _taskTextFieldController.text]);
                      Navigator.of(context).pop();
                    },
                  ),
                ],
              );
            },
          );
          setState(() {}); //to rebuild the future builder , better way of doing it getting data from dialog and then update database and ui
        },
        enableFeedback: true,
        child: const Icon(Icons.add),
      ),
    );
  }
}

CodePudding user response:

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

  • Related