Todo 리스트를 관리하는 provider 를 만들어 보자.
우선 모델을 만들고, 리스트 관리는 provider 를 이용하여 구현하였다.
개발환경 : 윈도우11, 안드로이드 스튜디오, flutter 2.10.3
소스코드 위치 - Release 03_model&todo_list · mike-bskim/todo_test (github.com)
todo_model.dart - 모델링
import 'package:equatable/equatable.dart';
import 'package:uuid/uuid.dart';
// unique 번호 생성
Uuid uuid = const Uuid();
class Todo extends Equatable{
final String id;
final String desc;
final bool completed;
// id 값을 넣지않으면 id값을 자동 초기화 함.
Todo({
String? id,
required this.desc,
this.completed = false,
}) : id = id ?? uuid.v4();
@override
// TODO: implement props
List<Object?> get props => [id, desc, completed];
@override
String toString() {
return 'Todo{id: $id, completed: $completed, desc: $desc}';
}
}
todo_list.dart - 리스트 관리
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import '../models/todo_model.dart';
class TodoListState extends Equatable {
final List<Todo> todos;
const TodoListState({
required this.todos,
});
factory TodoListState.init() {
return TodoListState(todos: [
Todo(id: '1', desc: 'Clean the room'),
Todo(id: '2', desc: 'Wash the dish'),
Todo(id: '3', desc: 'Do homework'),
]);
}
@override
List<Object> get props => [todos];
// @override
// bool get stringify => true;
@override
String toString() {
return 'TodoListState{todos: $todos}';
}
TodoListState copyWith({
List<Todo>? todos,
}) {
return TodoListState(
todos: todos ?? this.todos,
);
}
}
class TodoList with ChangeNotifier {
TodoListState _state = TodoListState.init();
TodoListState get state => _state;
// 리스트 추가
void addTodo(String todoDesc) {
int? newNum;
if(_state.todos.isEmpty){
newNum = 1;
} else {
// 마지막 id 에서 1 증가
newNum = int.parse(_state.todos.last.id)+1;
}
final newTodo = Todo(id: newNum.toString(),desc: todoDesc);
final newTodos = [..._state.todos, newTodo];
// 리스트 새로 복사&생성
_state = _state.copyWith(todos: newTodos);
notifyListeners();
}
void toggleTodo(String id) {
final newTodos = _state.todos.map((Todo todo) {
// 해당 리스트만 토글
if (todo.id == id) {
return Todo(
id: id,
desc: todo.desc,
completed: !todo.completed,
);
}
// 다른 리스트는 그대로 리턴
return todo;
}).toList();
// 토글된 리스트 새로 복사&생성
_state = _state.copyWith(todos: newTodos);
notifyListeners();
}
}
todos_screen.dart 수정
class CreateTodo extends StatefulWidget {
const CreateTodo({Key? key}) : super(key: key);
@override
_CreateTodoState createState() => _CreateTodoState();
}
class _CreateTodoState extends State<CreateTodo> {
final newTodoController = TextEditingController();
@override
void dispose() {
newTodoController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextFormField(
controller: newTodoController,
decoration: const InputDecoration(labelText: 'What to do?'),
onFieldSubmitted: (String? todoDesc) {
if (todoDesc != null && todoDesc.trim().isNotEmpty) {
debugPrint('CreateTodo Clicked: ${todoDesc.toString()}');
context.read<TodoList>().addTodo(todoDesc);
newTodoController.clear();
}
},
);
}
}
// => todo_model.dart
// class Todo {
// String id;
// String desc;
// bool completed;
//
// Todo({
// required this.id,
// required this.desc,
// this.completed = false,
// });
//
// }
//
// List<Todo> todos = [
// Todo(id: '1', desc: 'Clean the room'),
// Todo(id: '2', desc: 'Wash the dish'),
// Todo(id: '3', desc: 'Do homework'),
// ];
class ShowTodos extends StatelessWidget {
const ShowTodos({Key? key}) : super(key: key);
Widget showBackground(int direction) {
return Container(
margin: const EdgeInsets.all(4.0),
padding: const EdgeInsets.symmetric(horizontal: 10.0),
color: Colors.red,
alignment: direction == 0 ? Alignment.centerLeft : Alignment.centerRight,
child: const Icon(
Icons.delete,
size: 30.0,
color: Colors.white,
),
);
}
@override
Widget build(BuildContext context) {
// 현재는 초기화 되는 부분에서 가져오지만 차후에는 필더리스트 가져오기.
final todos = context.watch<TodoList>().state.todos;
return ListView.separated(
primary: false,
shrinkWrap: true,
itemCount: todos.length,
separatorBuilder: (BuildContext context, int index) {
return const Divider(color: Colors.grey);
},
itemBuilder: (BuildContext context, int index) {
return TodoItem(todo: todos[index]);
},
);
}
}
class TodoItem extends StatefulWidget {
final Todo todo;
const TodoItem({Key? key, required this.todo}) : super(key: key);
@override
_TodoItemState createState() => _TodoItemState();
}
class _TodoItemState extends State<TodoItem> {
@override
Widget build(BuildContext context) {
debugPrint('todo list : ${widget.todo}');
return ListTile(
leading: Checkbox(
value: widget.todo.completed,
onChanged: (bool? checked) {
// 토글함수
context.read<TodoList>().toggleTodo(widget.todo.id);
debugPrint(
'value(${widget.todo.desc}): ${widget.todo.completed.toString()}');
// provider 처리해서 필요없음
// setState(() {});
},
),
title: Text(widget.todo.desc),
);
}
}
[참고자료] udemy - Flutter Provider Essential 코스 (Korean)
'Flutter > 10 app Todo with provider' 카테고리의 다른 글
[Flutter] App Todo(with Provider) - 6단계 리스트 삭제, 편집 (0) | 2022.05.20 |
---|---|
[Flutter] App Todo(with Provider) - 5단계 할일 개수 표시 (0) | 2022.05.20 |
[Flutter] App Todo(with Provider) - 4단계 검색 (0) | 2022.05.20 |
[Flutter] App Todo(with Provider) - 3단계 필터 및 리스트, cascade notation (0) | 2022.05.18 |
[Flutter] App Todo(with Provider) - 1단계 화면구성 (0) | 2022.05.13 |