Я совсем новичок в sqlite
и flutter
. Я пытался создать локальный database
для своего приложения flutter to do. Поэтому я посмотрел несколько видеороликов на YouTube и начал реализовывать базу данных с помощью плагина flutter sqflite
. Все работало нормально, потому что все, что я сделал, это скопировал код you tubers, пока мне не пришлось добавить в код дополнительный параметр, который является логическим, чтобы отслеживать статус задачи (например, выполнил задачу или нет). Я использовал значение int
для сохранения bool
, а sqlite
не поддерживает значения boolean
. Я использовал два functions
, один для обновления text
, а другой для обновления значения switch
.
А во-вторых, когда я нажимаю на переключатель, срабатывают все переключатели в list
. Я тоже хочу решить этот вопрос.
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,
};
}
}
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,
},
);
}
}
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;
});
},
),
),
);
}
}
Я нашел ответ: (на случай, если у кого-то возник такой же вопрос)
Я удалил логическое значение isDone
из виджета приложения материалов и вместо того, чтобы назначить переключатель val
этому bool
, я присвоил его значению базы данных task.isDone
. Чтобы избежать автоматического срабатывания переключателя, я разобрал Taskdb
на 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);
});