Skip to content

Instantly share code, notes, and snippets.

@koboolean
Created June 17, 2022 11:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save koboolean/2bc4a15cad1f9a71c82beb4fdd133fa5 to your computer and use it in GitHub Desktop.
Save koboolean/2bc4a15cad1f9a71c82beb4fdd133fa5 to your computer and use it in GitHub Desktop.
flutter diary project
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:table_calendar/table_calendar.dart';
class Diary {
String text;
DateTime createdAt;
Diary({
required this.text,
required this.createdAt,
});
Map<String, dynamic> toJson() {
return {
"text": text,
"createdAt": createdAt.toString(),
};
}
factory Diary.fromJson(Map<String, dynamic> jsonMap) {
return Diary(
text: jsonMap['text'],
createdAt: DateTime.parse(jsonMap['createdAt']),
);
}
}
class DiaryService extends ChangeNotifier {
SharedPreferences prefs;
List<Diary> diaryList = [];
DiaryService(this.prefs) {
List<String> strintDiaryList = prefs.getStringList("diaryList") ?? [];
for (String s in strintDiaryList) {
Map<String, dynamic> jsonMap = jsonDecode(s);
Diary diary = Diary.fromJson(jsonMap);
diaryList.add(diary);
}
}
List<Diary> getByDate(DateTime date) {
return diaryList
.where((diary) => isSameDay(date, diary.createdAt))
.toList();
}
void create(String text, DateTime selectedDate) {
DateTime now = DateTime.now();
DateTime createdAt = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
now.hour,
now.minute,
now.second,
);
Diary diary = Diary(
text: text,
createdAt: createdAt,
);
diaryList.add(diary);
notifyListeners();
savePreferences();
}
void update(DateTime createdAt, String newContent) {
Diary diary = diaryList.firstWhere((diary) => diary.createdAt == createdAt);
diary.text = newContent;
notifyListeners();
savePreferences();
}
void delete(DateTime createdAt) {
diaryList.removeWhere((diary) => diary.createdAt == createdAt);
notifyListeners();
savePreferences();
}
void savePreferences() {
List<String> stringDiaryList = [];
for (Diary diary in diaryList) {
Map<String, dynamic> jsonMap = diary.toJson();
String stringDiary = jsonEncode(jsonMap);
stringDiaryList.add(stringDiary);
}
prefs.setStringList("diaryList", stringDiaryList);
}
}
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:table_calendar/table_calendar.dart';
import 'diary_service.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
CalendarFormat calendarFormat = CalendarFormat.month;
DateTime selectedDate = DateTime.now();
TextEditingController createControl = TextEditingController();
TextEditingController updateControl = TextEditingController();
@override
Widget build(BuildContext context) {
return Consumer<DiaryService>(
builder: (context, diaryService, child) {
List<Diary> diaryList = diaryService.getByDate(selectedDate);
return Scaffold(
// 키보드가 올라올 때 화면 밀지 않도록 만들기(overflow 방지)
resizeToAvoidBottomInset: false,
body: SafeArea(
child: Column(
children: [
/// 달력
TableCalendar(
firstDay: DateTime.utc(2010, 10, 16),
lastDay: DateTime.utc(2030, 3, 14),
focusedDay: selectedDate,
calendarFormat: calendarFormat,
onFormatChanged: (format) {
// 달력 형식 변경
setState(() {
calendarFormat = format;
});
},
eventLoader: (date) {
// 각 날짜에 해당하는 diaryList 보여주기
return diaryService.getByDate(date);
},
calendarStyle: CalendarStyle(
// today 색상 제거
todayTextStyle: TextStyle(color: Colors.black),
todayDecoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
),
selectedDayPredicate: (day) {
return isSameDay(selectedDate, day);
},
onDaySelected: (_, focusedDay) {
setState(() {
selectedDate = focusedDay;
});
},
),
Divider(height: 1),
/// 선택한 날짜의 일기 목록
Expanded(
child: diaryList.isEmpty
? Center(
child: Text(
"한 줄 일기를 작성해주세요.",
style: TextStyle(
color: Colors.grey,
fontSize: 18,
),
),
)
: ListView.separated(
itemCount: diaryList.length,
itemBuilder: (context, index) {
// 역순으로 보여주기
int i = diaryList.length - index - 1;
Diary diary = diaryList[i];
return ListTile(
/// text
title: Text(
diary.text,
style: TextStyle(
fontSize: 24,
color: Colors.black,
),
),
/// createdAt
trailing: Text(
DateFormat('kk:mm').format(diary.createdAt),
style: TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
/// 클릭하여 update
onTap: () {
showUpdateDialog(diaryService, diary);
},
/// 꾹 누르면 delete
onLongPress: () {
showDeleteDialog(diaryService, diary);
},
);
},
separatorBuilder: (BuildContext context, int index) {
// item 사이에 Divider 추가
return Divider(height: 1);
},
),
),
],
),
),
/// Floating Action Button
floatingActionButton: FloatingActionButton(
child: Icon(Icons.create),
backgroundColor: Colors.indigo,
onPressed: () {
showCreateDialog(diaryService);
},
),
);
},
);
}
void createDiary(DiaryService diaryService) {
// 앞뒤 공백 삭제
String newText = createControl.text.trim();
if (newText.isNotEmpty) {
diaryService.create(newText, selectedDate);
createControl.text = "";
}
}
void updateDiary(DiaryService diaryService, Diary diary) {
// 앞뒤 공백 삭제
String updatedText = updateControl.text.trim();
if (updatedText.isNotEmpty) {
diaryService.update(
diary.createdAt,
updatedText,
);
}
}
void showCreateDialog(DiaryService diaryService) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("일기 작성"),
content: TextField(
controller: createControl,
autofocus: true,
// 커서 색상
cursorColor: Colors.indigo,
decoration: InputDecoration(
hintText: "한 줄 일기를 작성해주세요.",
// 포커스 되었을 때 밑줄 색상
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.indigo),
),
),
onSubmitted: (_) {
// 엔터 누를 때 작성하기
createDiary(diaryService);
Navigator.pop(context);
},
),
actions: [
/// 취소 버튼
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(
"취소",
style: TextStyle(color: Colors.indigo),
),
),
/// 작성 버튼
TextButton(
onPressed: () {
createDiary(diaryService);
Navigator.pop(context);
},
child: Text(
"작성",
style: TextStyle(color: Colors.indigo),
),
),
],
);
},
);
}
/// 수정 다이얼로그 보여주기
void showUpdateDialog(DiaryService diaryService, Diary diary) {
showDialog(
context: context,
builder: (context) {
updateControl.text = diary.text;
return AlertDialog(
title: Text("일기 수정"),
content: TextField(
autofocus: true,
controller: updateControl,
// 커서 색상
cursorColor: Colors.indigo,
decoration: InputDecoration(
hintText: "한 줄 일기를 작성해 주세요.",
// 포커스 되었을 때 밑줄 색상
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.indigo),
),
),
onSubmitted: (v) {
// 엔터 누를 때 수정하기
updateDiary(diaryService, diary);
Navigator.pop(context);
},
),
actions: [
/// 취소 버튼
TextButton(
child: Text(
"취소",
style: TextStyle(
fontSize: 18,
color: Colors.indigo,
),
),
onPressed: () => Navigator.pop(context),
),
/// 수정 버튼
TextButton(
child: Text(
"수정",
style: TextStyle(
fontSize: 18,
color: Colors.indigo,
),
),
onPressed: () {
// 수정하기
updateDiary(diaryService, diary);
Navigator.pop(context);
},
),
],
);
},
);
}
/// 삭제 다이얼로그 보여주기
void showDeleteDialog(DiaryService diaryService, Diary diary) {
showDialog(
context: context,
builder: (context) {
updateControl.text = diary.text;
return AlertDialog(
title: Text("일기 삭제"),
content: Text('"${diary.text}"를 삭제하시겠습니까?'),
actions: [
TextButton(
child: Text(
"취소",
style: TextStyle(
fontSize: 18,
color: Colors.indigo,
),
),
onPressed: () => Navigator.pop(context),
),
/// Delete
TextButton(
child: Text(
"삭제",
style: TextStyle(
fontSize: 18,
color: Colors.indigo,
),
),
onPressed: () {
diaryService.delete(diary.createdAt);
Navigator.pop(context);
},
),
],
);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'diary_service.dart';
import 'home_page.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// sharedPreferences 인스턴스 불러오기
SharedPreferences prefs = await SharedPreferences.getInstance();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => DiaryService(prefs)),
],
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment