Home > Mobile >  Not saving the flutter switch value to sqflite database
Not saving the flutter switch value to sqflite database

Time:05-09

I am a completely a beginner to sqlite and flutter. I was trying to create a local database to my flutter to do app. So I watched some youtube videos and started to implementing a database using flutter sqflite plugin. Everything worked fine because all I did was copy typing the you tubers code, until I had to add an extra parameter to the code which is a boolean, in order to track the status of the task (like done the task or not). I used an int value to save the bool, while sqlite does not supports boolean values. I used two functions, one to update the text and the other to update the switch value.

And secondly when I tap on a switch it triggers all the switches in the list. I want to solve that issue as well.

gif

Model class for the Task

class Tasksdb {
  final int? id;
  final String taskName;
  bool isDone;

  Tasksdb({
    this.id,
    required this.taskName,
    required this.isDone,
  });

  factory Tasksdb.fromMap(Map<String, dynamic> json) => Tasksdb(
      id: json['id'],
      taskName: json['taskName'],
      isDone: (json['isDone'] as int) == 0 ? false : true);

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'taskName': taskName,
      'isDone': isDone,
    };
  }
}  

DatabaseHelper class

 class DatabaseHelper {
  DatabaseHelper._privateConstructor();
  static final DatabaseHelper instance = DatabaseHelper._privateConstructor();

  static Database? _database;
  Future<Database> get database async => _database ??= await _initDatabase();

  Future<Database> _initDatabase() async {
    Directory documentsDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentsDirectory.path, 'tasks.db');
    return await openDatabase(
      path,
      version: 1,
      onCreate: _onCreate,
    );
  }

  Future _onCreate(Database db, int version) async {
    await db.execute('''
      CREATE TABLE IF NOT EXISTS "taskstable" (
    "id"    INTEGER,
    "taskName"  TEXT,
    "isDone"    INTEGER NOT NULL DEFAULT 0,
    PRIMARY KEY("id" AUTOINCREMENT)
);
      ''');
  }

  Future<List<Tasksdb>> getTasks() async {
    Database db = await instance.database;
    var tasksQuery = await db.query(
      'taskstable',
    );
    List<Tasksdb> taskList = tasksQuery.isNotEmpty
        ? tasksQuery.map((c) => Tasksdb.fromMap(c)).toList()
        : [];
    return taskList;
  }

  Future<int> add(Tasksdb task) async {
    Database db = await instance.database;
    return await db.insert('taskstable', {
      'id': task.id,
      'taskName': task.taskName,
      'isDone': 0,
    });
  }


  Future<int> update(Tasksdb task) async {
    Database db = await instance.database;
    return await db.update(
      'taskstable',
      task.toMap(),
      where: "id = ?",
      whereArgs: [task.id],
    );
  }

  Future<int> updateIsDone(bool isDoneTodb) async {
    Database db = await instance.database;
    return await db.update(
      'taskstable',
      {
        'isDone': isDoneTodb == true ? 1 : 0,
      },
    );
  }
}

HomeScreen widget

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

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

class _SqliteAppState extends State<SqliteApp> {
  int? selectedId;
  final textController = TextEditingController();
  bool isDone = false;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: TextField(
            controller: textController,
          ),
        ),
        body: Center(
          child: FutureBuilder<List<Tasksdb>>(
              future: DatabaseHelper.instance.getTasks(),
              builder: (BuildContext context,
                  AsyncSnapshot<List<Tasksdb>> snapshot) {
                if (!snapshot.hasData) {
                  return const Center(child: Text('Loading...'));
                }
                return snapshot.data!.isEmpty
                    ? const Center(child: Text('No tasks in List.'))
                    : ListView(
                        children: snapshot.data!.map((task) {
                          return Center(
                            child: Card(
                              color: selectedId == task.id
                                  ? Colors.green
                                  : Colors.yellow,
                              child: ListTile(
                                trailing: Switch(   //the problem is here, doesn't save to db
                                    value: isDone,
                                    onChanged: (val) async {
                                      setState(() {
                                        isDone = val;
                                      });
                                      await DatabaseHelper.instance
                                          .updateIsDone(
                                        isDone,
                                      );
                                    }),
                                title: Text(task.taskName),
                                onTap: () {
                                  setState(() {
                                    if (selectedId == null) {
                                      textController.text = task.taskName;
                                      selectedId = task.id;
                                    } else {
                                      textController.text = 'add something';
                                      selectedId = null;
                                    }
                                  });
                                },
                              ),
                            ),
                          );
                        }).toList(),
                      );
              }),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () async {
            await DatabaseHelper.instance.add(
              Tasksdb(
                taskName: textController.text,
                isDone: false,
              ),
            );
            setState(() {
              textController.clear();
              selectedId = null;
            });
          },
        ),
      ),
    );
  }
}

CodePudding user response:

I found the answer: (in case of if someone had the same question) I removed the bool isDone from the material app widget, and instead of assigning the switch val to that bool I assigned it to database's task.isDone value. To avoid switch's auto trigger, I parsed the Taskdb to the updateIsDone function

Future<int> updateIsDone(Tasksdb task, bool isDoneTodb) async {
    Database db = await instance.database;
    return await db.update(
        'taskstable',
        {
          'isDone': isDoneTodb == true ? 1 : 0,
        },
        where: "id = ?",
        whereArgs: [task.id]);
  }

...

Switch(
     value: task.isDone,
     onChanged: (val) async {
            setState(() {
                 task.isDone = val;
            });
     await DatabaseHelper.instance
     .updateIsDone(task, task.isDone);
       }); 
  • Related