์ค๋์ ๋ชฉํ : ์ผ์ ์ญ์ ๊ธฐ๋ฅ๊ณผ 0๊ฐ๋ก ๊ณ ์ ๋์ด ์๋ ์ผ์ ๊ฐ์ ์ค์๊ฐ ๋ฐ์ดํฐ ๊ฐ์๋ก ์ ๋ฐ์ดํธํ๊ธฐ
createState() : ์์ ฏ์ด ๋น๋ํ ๋ ํธ์ถ๋๋ StatefulWidget ์ฌ์ฉ ์ ํ์ ๊ตฌํํ๋ ๋ฉ์๋
DateTime : ๋ ์ง, ์๊ฐ ์ ๊ณตํ๋ ํด๋์ค
Scaffold : ๊ธฐ๋ณธ ๋ผ๋ ์์ ฏ
floatingActionButton : ์ฐ์ธก ํ๋จ์ ๋ ์๋ ๋ฒํผ
โญ๏ธStreamBuilderโญ๏ธ : ์ค์๊ฐ ๋ฐ์ดํฐ๋ฅผ ํ๋ฉด์ ์ ๋ฐ์ดํธํ ๋ ์ฌ์ฉํ๋ ์์ ฏ
/screen/home_screen.dart
import 'package:flutter/material.dart';
import 'package:calendar_scheduler/component/main_calendar.dart';
import 'package:calendar_scheduler/component/schedule_card.dart';
import 'package:calendar_scheduler/component/today_banner.dart';
import 'package:calendar_scheduler/component/schedule_bottom_sheet.dart';
import 'package:calendar_scheduler/const/colors.dart';
import 'package:get_it/get_it.dart';
import 'package:calendar_scheduler/database/drift_database.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen>{
DateTime selectedDate = DateTime.utc(
DateTime.now().year,
DateTime.now().month,
DateTime.now().day,
);
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: PRIMARY_COLOR,
onPressed: (){
showModalBottomSheet(
context: context,
isDismissible : true,
builder: (_) =>ScheduleBottomSheet(
selectedDate: selectedDate,
),
isScrollControlled: true, // ํ๋ฉด ์ต๋ ๋์ด๋ฅผ : ํ๋ฉด ์ ์ฒด๋ก ๋ณ๊ฒฝ
);
},
child: Icon(
Icons.add,
),
),
body: SafeArea(
child: Column(
children: [
MainCalendar(
selectedDate: selectedDate,
//์ ํ๋ ๋ ์ง ์ ๋ฌ ์ฝ๋
onDaySelected: onDaySelected,
),
SizedBox(height:8),
StreamBuilder<List<Schedule>>(
stream: GetIt.I<LocalDatabase>().watchSchedules(selectedDate),
builder: (context, snapshoot){
return TodayBanner(
selectedDate: selectedDate,
count: snapshoot.data?.length ?? 0,
);
},
),
SizedBox(height:8),
Expanded( //์ปฌ๋ผ์์ ๋จ์ ๊ณต๊ฐ ์ ์ฒด๋ฅผ ์ฐจ์งํ๊ฒ ํ๋ ๊ณต๊ฐ
child: StreamBuilder<List<Schedule>>( // ์คํธ๋ฆผ๋น๋ : ๋ฐ๋๋๋ง๋ค ์๋ ค์ค
//์คํธ๋ฆผํ ๋ฐ์ดํฐ๋ฅผ
// ์คํธ๋ฆผ: ๊ฐ ๋ถํดํ ๊ฒ์ ..
stream: GetIt.I<LocalDatabase>().watchSchedules(selectedDate),
// ๋ฐ์ดํฐ ๋ฒ ์ด์ค์์ ๊ฐ
// ์๋ก ์ถ๊ฐ๋๊ฑฐ๋ ์์ ๋๋ฉด ์๋ ค๋ฌ๋ผ๊ณ ํจ
builder: (context, snapshot){
// snapshot : ๋ฐ์ดํฐ ์์ดใด์ง, ์๋ฌ ์ด๋ค๊ฑด์ง
if (!snapshot.hasData) {
return Container(); // ์์ผ๋ฉด : ๋นํ๋ฉด
}
return ListView.builder(
itemCount:snapshot.data!.length,
itemBuilder: (context, index){
final schedule = snapshot.data![index]; // ์ผ์ ๋ชฉ๋ก์ด ๋ค์ด์ด
return Dismissible(
key:ObjectKey(schedule.id), //์ ๋ํฌํ ํค๊ฐ
direction:DismissDirection.startToEnd,
onDismissed: (DismissDirection direction) {
GetIt.I<LocalDatabase>()
.removeSchedule(schedule.id);
},
child: Padding(
padding: const EdgeInsets.only(bottom: 8, left:8,
right: 8),
child: ScheduleCard(
startTime: schedule.startTime,
endTime: schedule.endTime,
content: schedule.content
),
),
);
},
);
},
)
)
],
),
),
);
}
void onDaySelected(DateTime selectedDate, DateTime focusedDate) {
// ๋ ์ง ์ ํ๋ ๋๋ง๋ค ์คํํ ํจ์
setState(() {
this.selectedDate = selectedDate;
});
}
}
=> ๋ ์ง ์ ํ, ์ผ์ ์ถ๊ฐ,์ญ์ ,๋ชฉ๋กํ์ ๋ด๋นํ๋ ์ฑ์ ๋ฉ์ธ ํ๋ฉด
/screen/home_screen.dart
return Dismissible(
key:ObjectKey(schedule.id), //์ ๋ํฌํ ํค๊ฐ
direction:DismissDirection.startToEnd,
onDismissed: (DismissDirection direction) {
GetIt.I<LocalDatabase>()
.removeSchedule(schedule.id);
},
child: Padding(
padding: const EdgeInsets.only(bottom: 8, left:8,
right: 8),
child: ScheduleCard(
startTime: schedule.startTime,
endTime: schedule.endTime,
content: schedule.content
),
),
);
GetIt.I<LocalDatabase>()
.removeSchedule(schedule.id); //์ค์ ์ญ์ ๊ธฐ๋ฅ schedule.id ๊ณ ์ ํ ๋ฒํธ
},
StreamBuilder<List<Schedule>>(
stream: GetIt.I<LocalDatabase>().watchSchedules(selectedDate),
builder: (context, snapshoot){
return TodayBanner(
selectedDate: selectedDate,
count: snapshoot.data?.length ?? 0,
);
},
),
| ์ฝ๋ | ์ญํ | ๋น๊ณ |
|---|---|---|
| Dismissible | ์ผ์ ์ญ์ | ์ผ์ ์ ์ผ์ชฝ์์ ์ค๋ฅธ์ชฝ์ผ๋ก ๋ฐ์์ ๋ ์ผ์ ์ญ์ |
| direction:DismissDirection.startToEnd | ์ผ์ ์ญ์ | ๋ฏธ๋ ๋ฐฉํฅ ์ง์ |
| removeSchedule(schedule.id) | ์ญ์ ์กฐ๊ฑด | DB์์ ์ฃผ๋ ๊ณ ์ ํ ๋ฒํธ๋ฅผ ์ง์ ํ์ฌ ํด๋น ๋ฒํธ ์ผ์ ์ญ์ |
| count: snapshoot.data?.length ?? 0 | ์ผ์ ๊ฐ์ ์ธ๊ธฐ | DB์์ ๊ฐ์ ธ์จ ์ผ์ ๋ชฉ๋ก์ด null์ด ์๋๋ฉด ๊ฐ์ ๊ฐ์ ธ์ด, null์ด๋ฉด 0์ผ๋ก ํ์ |
- selectedDate๋ฅผ ์ค๋ ๋ ์ง๋ก ์ด๊ธฐํ
- ํ๋ฉด ๋ ๋๋ง(ํ๋ฉด ๊ทธ๋ฆฌ๊ธฐ)
- ๋ฌ๋ ฅ์์ ๋ ์ง ์ ํ
- onDaySelected ์คํ โ setState๋ก selectedDate ์ ๋ฐ์ดํธ
โ MainCalendar ์ ํ ๋ ์ง ํ๋์์ผ๋ก
โ TodayBanner ๋ ์ง ๋ฐ๋
โ StreamBuilder๊ฐ ์ ๋ ์ง ์ผ์ ์๋์ผ๋ก ๋ถ๋ฌ์ด- ์ผ์ ์ถ๊ฐ ๋ฒํผ ๋๋ฆ
ScheduleBottomSheet ์ฌ๋ผ์ด
โ ์์์๊ฐ/์ข ๋ฃ์๊ฐ/๋ด์ฉ ์ ๋ ฅ
โ ์ ์ฅ ๋ฒํผ ํด๋ฆญ โ DB์ ์ ์ฅ
โ StreamBuilder ๋ณํ ๊ฐ์ง
โ ScheduleCard ๋ชฉ๋ก์ ์๋ ์ถ๊ฐ
โ TodayBanner ๊ฐ์ +1 ์นด์ดํธ- ์ผ์ ์ญ์
ScheduleCard ์ค๋ฅธ์ชฝ์ผ๋ก ๋ฐ๊ธฐ
โ onDismissed ์คํ
โ removeSchedule(schedule.id)๋ก DB์์ ์ญ์
โ StreamBuilder ๋ณํ ๊ฐ์ง
โ ๋ชฉ๋ก์์ ์๋์ผ๋ก ์ฌ๋ผ์ง
โ TodayBanner ๊ฐ์ -1 ์ค์
direction:DismissDirection.endToStart,
๋ฐฉํฅ์ startToEnd์์ endToStart, up, down์ผ๋ก ๋ฐ๊ฟ์ ์ญ์ ํ๊ธฐ ์ํด ์ผ์ ์นด๋๋ฅผ ๋ฏธ๋ ๋ฐฉํฅ์ ๋ฐ๊ฟ๋ดค๋ค.
| ์ฝ๋ | ๋ฏธ๋ ๋ฐฉํฅ |
|---|---|
| startToEnd | ์ผ์ชฝ -> ์ค๋ฅธ์ชฝ |
| endToStart | ์ค๋ฅธ์ชฝ -> ์ผ์ชฝ |
| up | ์๋ -> ์ |
| down | ์ -> ์๋ |
๐จ์๋ฌ๐จ : โ
StreamBuilder ๊ฐ๋ ์ ์๋ก ๋ฐฐ์ ๋ค. StreamBuilder๋ ๋ฐ์ดํฐ๊ฐ ๊ณ์ ๋ณ๊ฒฝ๋๊ธฐ ๋๋ฌธ์ ์ฌ์ฉํ๋ค. Stream์ ๋ฐ์ดํฐ๊ฐ ๋ค์ด์ฌ ๋๋ง๋ค builder๋ฅผ ์คํํ๋ค. snapshot์ ๋ค์ด์จ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค๊ฐ StreamBuilder๊ฐ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์ค๋ฉด ์๋ก์ด ๋ฐ์ดํฐ๋ก ๊ฐฑ์ ํ์ฌ ๊ฐ์ง๋ก ์๋๋ค. snapshot์ ๋ฐ์ดํฐ๋ฟ๋ง ์๋๋ผ ๋ฐ์ดํฐ ์ํ๋ ๊ฐ์ง๊ณ ์๋๋ค. (hasError, hasData, data)
์ผ์ ์ญ์

์ผ์ ๊ฐ์ ์ค์๊ฐ ๋ฐ์ดํฐ๋ก ๋ฐ์
