To-do List: Tasks Left
Part of the Projects section of Coddy's Flutter journey. Lesson 4 of 36.
A glance at the screen should tell you how much is left to do. The answer is the number of tasks that are not done, and you can work it out from the list every time the screen is built.
A getter is the place for it. It reads like a field but runs its code each time you use it, so it is always up to date:
int get _left => _tasks.where((task) => !task.done).length;There is no extra variable to keep in step and no setState of its own: ticking a task already calls setState, the screen is rebuilt, and the getter counts again.
One detail makes it read like a person wrote it: "1 task left", not "1 tasks left". A conditional picks the right words.
Challenge
MediumShow what is left:
- add a getter
_leftthat counts the tasks that are not done - between the field and the list, show it in a
Textsuch as3 tasks left, in aRowwith 16 pixels of padding on the sides and 8 above and below - for exactly one task, say
1 task left
Try it yourself
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
),
home: const TodoScreen(),
);
}
}
class Task {
Task(this.title);
final String title;
bool done = false;
}
class TodoScreen extends StatefulWidget {
const TodoScreen({super.key});
@override
State<TodoScreen> createState() => _TodoScreenState();
}
class _TodoScreenState extends State<TodoScreen> {
final List<Task> _tasks = [Task('Buy milk'), Task('Walk the dog'), Task('Read a book')];
final _controller = TextEditingController();
void _addTask() {
setState(() {
_tasks.add(Task(_controller.text));
});
_controller.clear();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('My Tasks')),
body: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: const InputDecoration(
labelText: 'New task',
border: OutlineInputBorder(),
),
),
),
const SizedBox(width: 8),
IconButton.filled(
onPressed: _addTask,
icon: const Icon(Icons.add),
),
],
),
),
Expanded(
child: ListView.builder(
itemCount: _tasks.length,
itemBuilder: (context, index) {
final task = _tasks[index];
return ListTile(
leading: Checkbox(
value: task.done,
onChanged: (value) {
setState(() {
task.done = value!;
});
},
),
title: Text(
task.title,
style: task.done
? const TextStyle(
decoration: TextDecoration.lineThrough,
color: Colors.grey,
)
: null,
),
);
},
),
),
],
),
);
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Projects
Practice on your own: Online Flutter compiler