main.dart
import 'package:flutter/material.dart';
import 'package:todo/screens/homepage.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// var db = DatabaseConnect();
// // 插入一条简单的代办事项
// await db.insertTodo(Todo(
// id: 1,
// title: '这是一条简单的代办事项 ',
// creationDate: DateTime.now(),
// isChecked: false));
// print(await db.getTodo());
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
db_model.dart
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:todo/models/todo_model.dart';
class DatabaseConnect {
Database? _database;
// 创建getter 并打开数据库链接
Future<Database> get database async {
// 这是数据库的位置
final dbpath = await getDatabasesPath();
// 这是数据库的名称
const dbname = 'todo.db';
// 这是数据库的路径
final path = join(dbpath, dbname);
// 打开数据库链接
_database = await openDatabase(path, version: 1, onCreate: _createDB);
// 我们将分别创建数据库链接
return _database!;
}
// _create db 方法
// 在我们的数据库中创建表
Future<void> _createDB(Database db, int version) async {
// 确保我们在表中创建的列与todo_model字段匹配。
await db.execute('''
CREATE TABLE todo(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
creationDate TEXT,
isChecked INTEGER
)
''');
}
// 函数向数据库中添加数据
Future<void> insertTodo(Todo todo) async {
// 得到数据库链接
final db = await database;
// 插入代办事项
await db.insert(
'todo', // 表名
todo.toMap(), // 我们这todo_model中创建的函数
conflictAlgorithm: ConflictAlgorithm.replace, //去重
);
}
Future<void> deleteTodo(Todo todo) async {
final db = await database;
// 从数据库中按照待办事项的id将其删除
await db.delete(
'todo',
where: 'id == ?', // 此条件将检查todo列表中的id
whereArgs: [todo.id],
);
}
// 这个函数从数据库中获取全部待办事项
Future<List<Todo>> getTodo() async {
final db = await database;
// 查询数据库并将待办事项保存为映射列表
List<Map<String, dynamic>> items = await db.query(
'todo',
orderBy: 'id DESC', //将按照id进行降序排序
// 所以最新的代办事项将显示在顶部
);
return List.generate(
items.length,
(index) => Todo(
id: items[index]['id'],
title: items[index]['title'],
//现在是文本格式。我们把它转换成dateTime格式
creationDate: DateTime.parse(items[index]['creationDate']),
// 这将把integer转换为bool形式
isChecked: items[index]['isChecked'] == 1 ? true : false,
),
);
}
}
todo_model.dart
class Todo {
int? id;
final String title;
DateTime creationDate;
bool isChecked;
// 创建构造函数
Todo({
this.id,
required this.title,
required this.creationDate,
required this.isChecked,
});
// 为了将数据保存在数据库中,我们需要将它转换为map形式,所以创建下面这个函数
Map<String, dynamic> toMap() {
return {
'id': id,
'title': title,
'creationDate': creationDate.toString(),
'isChecked': isChecked ? 1 : 0,
};
}
// 这个函数只用于测试
@override
String toString() {
return 'Todo(id:$id,title:$id,creationDate:$creationDate,isChecked:$isChecked)';
}
}
homepage.dart
import 'package:flutter/material.dart';
import 'package:todo/models/db_model.dart';
import 'package:todo/models/todo_model.dart';
import 'package:todo/widgets/todo_list.dart';
import 'package:todo/widgets/user_input.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//我们必须在这里创建函数,两个小部件可以在这里进行通信
// 创建一个数据库对象,以便访问数据库函数
var db = DatabaseConnect();
// 添加待办事项的函数
void addItem(Todo todo) async {
await db.insertTodo(todo);
setState(() {});
}
// 删除待办事项函数
void deleteItem(Todo todo) async {
await db.deleteTodo(todo);
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Todo app'),
centerTitle: true,
),
body: Column(
children: [
TodoList(
deleteFunction: deleteItem,
insertFunction: addItem,
),
UserInput(insertFunction: addItem),
],
),
);
}
}
user_input.dart
import 'package:flutter/material.dart';
import 'package:todo/models/todo_model.dart';
class UserInput extends StatelessWidget {
var textController = TextEditingController();
final Function insertFunction; // 他是接收addItems的函数
UserInput({required this.insertFunction, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
// color: const Color(0xffeab5ff),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: Row(
children: [
// 这是输入框
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(width: 2.0, color: const Color(0xff8f8f8f))),
padding: const EdgeInsets.symmetric(horizontal: 5),
child: TextField(
controller: textController,
decoration: const InputDecoration(
hintText: 'add new todo',
border: InputBorder.none,
),
),
)),
const SizedBox(width: 10),
GestureDetector(
onTap: () {
var myTodo = Todo(
title: textController.text,
creationDate: DateTime.now(),
isChecked: false);
insertFunction(myTodo);
},
child: Container(
decoration: BoxDecoration(
color: Colors.lightBlue,
borderRadius: BorderRadius.circular(5)),
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 10,
),
child: const Text(
'Add',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
)
],
),
);
}
}
todo_card.dart
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:todo/models/todo_model.dart';
class TodoCard extends StatefulWidget {
// 创建属性
final int id;
final String title;
final DateTime creationDate;
bool isChecked;
final Function insertFunction;
final Function deleteFunction;
TodoCard(
{Key? key,
required this.id,
required this.title,
required this.isChecked,
required this.creationDate,
required this.insertFunction, // 它将处理复选框的变化
required this.deleteFunction}) // 它将处理删除按钮
: super(key: key);
@override
State<TodoCard> createState() => _TodoCardState();
}
class _TodoCardState extends State<TodoCard> {
@override
Widget build(BuildContext context) {
var anotherTodo = Todo(
id: widget.id,
title: widget.title,
creationDate: widget.creationDate,
isChecked: widget.isChecked,
);
return Card(
child: Row(
children: [
Container(
margin: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
child: Checkbox(
value: widget.isChecked,
onChanged: (bool? value) {
setState(() {
widget.isChecked = value!;
});
// 修改其他todo的isCheck值
anotherTodo.isChecked = value!;
// 向数据库中插入
widget.insertFunction(anotherTodo);
},
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.title,
style:
const TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
const SizedBox(height: 5),
Text(
DateFormat('dd MMM yyyy - hh:mm aa').format(widget.creationDate),
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: Color(0xff8f8f8f)),
),
],
)),
IconButton(
onPressed: () {
widget.deleteFunction(anotherTodo);
},
icon: const Icon(Icons.close))
],
),
);
}
}
todo_list.dart
import 'package:flutter/material.dart';
import 'package:todo/models/db_model.dart';
import 'package:todo/widgets/todo_card.dart';
class TodoList extends StatelessWidget {
// 创建一个数据库连接对象
// 要向下传递到todocard,首先我们的待办事项管理员必须接收这些函数
final Function insertFunction;
final Function deleteFunction;
var db = DatabaseConnect();
TodoList(
{Key? key, required this.insertFunction, required this.deleteFunction})
: super(key: key);
@override
Widget build(BuildContext context) {
return Expanded(
child: FutureBuilder(
future: db.getTodo(),
initialData: const [],
builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
var data = snapshot.data;
var datalength = data!.length;
return datalength == 0
? const Center(
child: Text("no data found"),
)
: ListView.builder(
itemCount: datalength,
itemBuilder: (context, i) => TodoCard(
id: data[i].id,
title: data[i].title,
isChecked: data[i].isChecked,
creationDate: data[i].creationDate,
insertFunction: insertFunction,
deleteFunction: deleteFunction,
));
},
));
}
}