'how to store tasks in temporary storage in flutter (use Shared preferences or something similar)

I created a program to create tasks, everything works as it should, I made such options as validation, deleting the task, changing the theme. But the problem is that when I restart the app all the tasks are deleted. I want to keep them in storage, temporarily or permanently. And I can't realize it. Someone may have experience as such to implement ?? or examples of similar problems. My goal is that after restarting the application, all tasks remain. My code

import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main ()  {

  runApp(MaterialApp(
    home: App(),
  ));
}

class ListItem{
  String todoText;
  bool todoCheck;
  ListItem(this.todoText, this.todoCheck);
}

class _strikeThrough extends StatelessWidget{

  final String todoText;
  final bool todoCheck;
  _strikeThrough(this.todoText, this.todoCheck) : super();

  Widget _widget(){
    if(todoCheck){
      return Text(
        todoText,
        style: TextStyle(
          fontSize: 22.0,

        ),
      );
    }
    else{
      return Text(
        todoText,
        style: TextStyle(
            fontSize: 22.0
        ),
      );
    }
  }

  @override
  Widget build(BuildContext context){
    return _widget();
  }
}

class App extends StatefulWidget{

  @override
  AppState createState(){
    return AppState();
  }
}
final ValueNotifier<ThemeMode> _notifier = ValueNotifier(ThemeMode.light);

class AppState extends State<App> {
  bool valText = true;
  var counter = 0;
  var IconsType =  Icons.wb_sunny  ;

  late Color ColorType =  Colors.black;

  var textController = TextEditingController();
  var popUpTextController = TextEditingController();


  List<ListItem> WidgetList = [];

  @override
  void dispose() {
    textController.dispose();
    popUpTextController.dispose();
    super.dispose();
  }
  
  @override
  void initState() {
    addToSP(defaultList).then((_) => getSP());
    super.initState();
  }
  Future<void> addToSP(List<List<ListItem>> tList) async {
    final prefs = await SharedPreferences.getInstance();
    prefs.setString('graphLists', jsonEncode(tList));
  }

  void getSP() async {
    final prefs = await SharedPreferences.getInstance();
    final List<dynamic> jsonData =
    jsonDecode(prefs.getString('graphLists') ?? '[]');
    WidgetList = jsonData.map<List<ListItem>>((jsonList) {
      return jsonList.map<TodoInfo>((jsonItem) {
        return ListItem.fromJson(jsonItem);
      }).toList();
    }).toList();
    setState(() {});
  }
  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<ThemeMode>(
        valueListenable: _notifier,
        builder: (_, mode, __) {
          return MaterialApp(
              theme: ThemeData.light(),
              darkTheme: ThemeData.dark(),
              themeMode: mode, // Decides which theme to show, light or dark.
              home: Scaffold(
                appBar: AppBar(
                  title: Text("Список задач"),
                  actions: <Widget>[
                    IconButton(
                        icon: Icon(IconsType,color : ColorType
                        ),
                        onPressed:() =>
                        {
                          if (_notifier.value == ThemeMode.light) {
                            _notifier.value =  ThemeMode.dark,
                            IconsType = Icons.dark_mode,
                            ColorType = Colors.white,

                          } else
                            {
                              _notifier.value =  ThemeMode.light,
                              IconsType = Icons.wb_sunny,
                              ColorType = Colors.black,
                            }
                        }
                    )
                  ],
                  //backgroundColor: Colors.orange[500],
                  iconTheme: IconThemeData(
                      color: Colors.white
                  ),
                ),
                body: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[

                    Container(
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.center,

                        children: <Widget>[
                          const Text(
                            "Tasks",
                            style: TextStyle(
                              fontSize: 70.0,
                              fontWeight: FontWeight.bold,
                              color: Colors.black,
                            ),
                          ),
                          IconButton(
                            color: Colors.black,
                            iconSize: 70,
                            constraints: const BoxConstraints(),
                            padding: EdgeInsets.fromLTRB(30.0, 10.0, 30, 10.0),
                            icon: const Icon(Icons.add_outlined),
                            onPressed: ()  {
                              if (textController.text.replaceAll(" ", "").isNotEmpty) {
                                WidgetList.insert(0, new ListItem(textController.text.replaceAll(" ", ""), false));
                                setState(() {
                                  valText = true;
                                  textController.clear();

                                });
                              }
                              else
                              {
                                setState(() {
                                  valText = false;
                                });
                              }
                            },


                          )




                        ],
                      ),

                    ),
                    Container(
                      width: MediaQuery
                          .of(context)
                          .size
                          .height * 0.45,
                      child: TextField(

                        style: TextStyle(
                          fontSize: 22.0,
                          //color: Theme.of(context).accentColor,
                        ),
                        controller: textController,
                        cursorWidth: 5.0,
                        autocorrect: true,
                        autofocus: true,
                        //onSubmitted: ,
                      ),
                    ),
                    Align(
                        child:
                        (valText == false) ?
                        Align(child: Text(("Задача пустая"),
                            style: TextStyle(
                                fontSize: 25.0, color: Colors.red)),
                            alignment: Alignment.center) :
                        Align(child: Text((""),),
                            alignment: Alignment.center)),
                    Expanded(
                      child: ReorderableListView(
                        children: <Widget>[
                          for(final widget in WidgetList)
                            GestureDetector(
                              key: Key(widget.todoText),
                              child: Dismissible(
                                key: Key(widget.todoText),
                                child: CheckboxListTile(
                                  controlAffinity: ListTileControlAffinity.leading,
                                  //key: ValueKey("Checkboxtile $widget"),
                                  value: widget.todoCheck,
                                  title: _strikeThrough(
                                      widget.todoText, widget.todoCheck),
                                  onChanged: (checkValue) {
                                    //_strikethrough toggle
                                    setState(() {
                                      if (!checkValue!) {
                                        widget.todoCheck = false;
                                      }
                                      else {
                                        widget.todoCheck = true;
                                      }
                                    });
                                  },
                                ),
                                background: Container(
                                  child: Icon(Icons.delete),
                                  alignment: Alignment.centerRight,
                                  color: Colors.redAccent,
                                ),

                                direction: DismissDirection.endToStart,
                                movementDuration: const Duration(
                                    milliseconds: 200),
                                onDismissed: (dismissDirection) { //Delete Todo
                                  WidgetList.remove(widget);

                                },
                              ),
                            )
                        ],
                        onReorder: (oldIndex, newIndex) {
                          setState(() {
                            if (newIndex > oldIndex) {
                              newIndex -= 1;
                            }
                            var replaceWiget = WidgetList.removeAt(oldIndex);
                            WidgetList.insert(newIndex, replaceWiget);
                          });
                        },
                      ),
                    )
                  ],
                ),
              )
          );
        }
    );
  }
}

class TodoInfo {
  String todoText;
  bool todoCheck;

  TodoInfo({
    required this.todoText,
    required this.todoCheck,

  });

  factory TodoInfo.fromJson(Map<String, dynamic> json) {
    return TodoInfo(
        todoText: json["todoText"],
        todoCheck: json["todoCheck"]);
  }

  factory TodoInfo.fromMap(Map<String, dynamic> map) => TodoInfo(
    todoText: map["todoText"]?? '',
    todoCheck: map["todoCheck"] ?? '',

  );
  Map<String, dynamic> toJson() {
    return {
      "todoText": todoText,
      "todoCheck": todoCheck
    };
  }

  @override
  String toString() => '{todoText: $todoText, todoCheck: $todoCheck}';
}

My skrin enter image description here



Solution 1:[1]

Here are some options for persistent memory.

Solution 2:[2]

You could use any of the storage functions/plugins available for flutter as per your need or interest. Some of them are

  1. Seflite
  2. Shared preferences
  3. Hive

Example on how to use Shared Preferences: LINK

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 user18309290
Solution 2