25일차 과제 2 - rlatkddbs99/Flutter GitHub Wiki
자꾸 오류가 떠서 보니 소켓통신에서 오류가 있었고 매니페스트에 인터넷 권한도 주고 해봐도 안되었었다. 보니까 자꾸 애뮬레이터를 오프라인 애뮬레이터로 띄워서 그런거였다;
main.dart
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:todo/page/mainPage.dart';
void main() async {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: mainPage(),
);
}
}
model/todo.dart
class Todo {
int userId;
int id;
String title;
bool completed;
Todo(
{required this.userId,
required this.id,
required this.title,
required this.completed});
factory Todo.fromMap(Map<String, dynamic> map) {
return Todo(
userId: map['userId'],
id: map['id'],
title: map['title'],
completed: map['completed']);
}
}
page/mainPage.dart
import 'dart:ffi';
import 'dart:ui';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:todo/model/todo.dart';
import 'package:todo/widget/filter_bottom_sheet.dart';
import '../widget/todo_card.dart';
class mainPage extends StatefulWidget {
const mainPage({super.key});
@override
State<mainPage> createState() => _mainPageState();
}
class _mainPageState extends State<mainPage> {
// Future<List<Todo>> readData() async { //오늘 강의는 퓨쳐 안쓰고 네트워크 데이터 요청하기
// Dio dio = Dio();
// var url = "https://jsonplaceholder.typicode.com/todos"; //url원하는 번호로 고치기
// var res = await dio.get(url);
// // print(res.data); //결과: 데이터 다 묶여서 뜸
// // print(res.data.runtimeType); //List<dynamic> , 변환과정 필요
// if (res.statusCode == 200) {
// var data = List<Map<String, dynamic>>.from(
// res.data); //List<Map<String,dynamic>>으로 바꿔줘야돼
// data.map((e) => Todo.fromMap(e)).toList();
// }
// return [];
// }
TodoFilter todoFilter = TodoFilter.all;
Dio dio = Dio();
var url = "https://jsonplaceholder.typicode.com/todos";
List<Todo> todos = []; //todo가 저장될 리스트
readTodos() async {
var res = await dio.get(url); //요청
if (res.statusCode == 200) {
//잘 받아오면
var data = List<Map<String, dynamic>>.from(res
.data); //데이터 형태 리스트로 바꾸기(list<dynamic>이 List<Map<String,dynamic>>으로)
setState(() {
todos = data.map((e) => Todo.fromMap(e)).toList();
});
//새로운값 대치, 새로고침 할 수 있도록 setState설정. 한번만 받는게 아니라 리프레쉬 누를때마다하려고
//futurebuilder가 아닌 이렇게
}
}
@override
void initState() {
super.initState();
readTodos();
}
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
foregroundColor: Colors.black,
elevation: 0,
flexibleSpace: ClipRRect(
//넘어가는 부분 자동으로 blur 처리
child: BackdropFilter(
//appBar뒤에 위젯넣기
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
),
),
title: Text("Todo App"),
actions: [
IconButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) => FilterBottomSheet(
filter: todoFilter, //일단 지금 설정한게 없기 때문에 기본값. all에 체크되어있음
onApply: (value) {
setState(() {
todoFilter = value; //내가 선택한 항목으로 화면 바꿀거야
});
})); //새로운값이 왔을 때 호출
},
icon: Icon(Icons.filter_alt)),
IconButton(
onPressed: () {
readTodos(); //새로고침해서 네트워크 데이터 다시가져와
},
icon: Icon(Icons.refresh_sharp))
],
),
body: ListView.builder(
//TodoCard랑 연결
itemBuilder: (context, index) =>
TodoCard(todo: filterMaker(todos)[index]), //해당하는 인덱스의 todo를 생성할거야
itemCount: filterMaker(todos)
.length, //네트워크에 모든 데이터가 있는데 이제 filterMaker를 호출해서 해당하는 인덱스만 출력하게된다
),
);
}
//todoFilter바꾸기
List<Todo> filterMaker(List<Todo> value) {
// todoFilter
switch (todoFilter) {
case TodoFilter.all:
return value;
case TodoFilter.completed:
return value
.where(
(element) => element.completed == true,
)
.toList();
case TodoFilter.incompleted:
return value
.where(
(element) => element.completed == false,
)
.toList();
}
}
}
widget/todo_card.dart
import 'package:flutter/material.dart';
import '../model/todo.dart';
class TodoCard extends StatelessWidget {
const TodoCard({super.key, required this.todo});
final Todo todo; //todo넘겨받기
@override
Widget build(BuildContext context) {
return Dismissible(
//swipe했을 때 해당내용 지움, 지워주긴하는데 눈에서만 보이지 않음
//onDisMissed속성을 이용해서 메모리에서도 같이 지워주는게 좋음
key: Key(todo.id.toString()),
child: Container(
margin: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: todo.completed ? Colors.green.shade100 : null, //성공이 된 todo의 색깔
border: todo.completed
? Border.all(
color: Colors.green,
)
: null,
borderRadius: BorderRadius.circular(8),
),
child: ListTile(
title: Text(
todo.title,
style: TextStyle(
color: todo.completed ? Colors.green : null, //이미끝난거면 초록색으로
fontWeight: FontWeight.bold,
),
),
trailing: todo.completed //성공한거면 아이콘 넣음
? const Icon(
Icons.check_circle,
color: Colors.green,
)
: null,
),
),
);
}
}
widget/filter_bottom_sheet.dart
import 'package:flutter/material.dart';
enum TodoFilter { all, completed, incompleted } //어떠한 값을 만들어 줄 때 설정해주는 상수값
class FilterBottomSheet extends StatefulWidget {
const FilterBottomSheet(
{Key? key, required this.filter, required this.onApply})
: super(key: key);
final TodoFilter filter; //enum으로 정의한 3개중에서만 가능
final Function(TodoFilter) onApply; //전달받는 함수
@override
State<FilterBottomSheet> createState() => _FilterBottomSheetState();
}
class _FilterBottomSheetState extends State<FilterBottomSheet> {
onApply(TodoFilter filter) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Filter applied: $filter'),
),
);
widget.onApply(filter);
Navigator.pop(context);
}
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: const Text('All'),
trailing: Checkbox(
value: widget.filter == TodoFilter.all,
onChanged: (value) {
//체크박스가 체크 되었을 떄
if (value == true) onApply(TodoFilter.all);
},
),
),
ListTile(
title: const Text('Completed'),
trailing: Checkbox(
value: widget.filter == TodoFilter.completed,
onChanged: (value) {
if (value == true) onApply(TodoFilter.completed);
},
),
),
ListTile(
title: const Text('InCompleted'),
trailing: Checkbox(
value: widget.filter == TodoFilter.incompleted,
onChanged: (value) {
if (value == true) onApply(TodoFilter.incompleted);
},
),
),
],
),
);
}
}