Flutter 캘린더 모달에서 할 일을 추가하는 방법: 편리한 To-Do 관리 기능 구현하기

2024. 12. 24. 15:41같이 공부합시다 - Flutter/Flutter로 To-Do 앱 만들기

728x90
반응형

안녕하세요! 😊
 
이번 글에서는 Flutter로 캘린더 모달 창에서 새로운 할 일을 바로 추가할 수 있는 기능을 구현하는 방법을 적용해 보겠습니다. 기존에는 캘린더를 보고 선택한 날짜의 할 일을 확인할 수만 있었지만, 이번에는 선택한 날짜에 할 일을 모달 창에서 바로 추가하는 기능을 추가해 사용성을 한 단계 업그레이드해 보겠습니다.
 
또한 메인 화면에서의 할 일 추가 버튼은 플로팅 버튼이며, 이번 내용과는 살짝 다릅니다.
메인 화면의 할 일 추가 버튼을 구경하고 싶으시다면 아래 글을 확인해 주세요 😁
 
To-Do List 앱 Step 2-0. 플로팅버튼 띄우기

To-Do List 앱 Step 2-0. 플로팅버튼 띄우기

서론이 너무 길었다.이제 드디어 기능을 넣어 볼 차례다. 두근두근 거리는구만. 구현하려는 내용은 다음과 같다.1. 화면 오른쪽 아래에 “+ (할 일 추가)” 플로팅 버튼 만들기.2. 플로팅 버튼을

steadybuilder.tistory.com

 
To-Do List 앱 Step 2-1. 플로팅버튼 > 다이얼로그 기본 호출 구조

To-Do List 앱 Step 2-1. 플로팅버튼 > 다이얼로그 기본 호출 구조

[ 만들어 보려는 내용 ]1 . 화면 오른쪽 아래에 “+ (할 일 추가)” 플로팅 버튼 만들기.2-1. 플로팅 버튼을 눌렀을 때 다이얼로그가 열리고, 사용자가 할 일을 입력할 수 있음.2-2. ‘취소’ 텍스트

steadybuilder.tistory.com

 
 
 
 


오늘 다룰 내용

  1. 왜 캘린더에서 할 일 추가가 필요할까요?
  2. 할 일 추가 버튼 구현하기
  3. UI/UX를 개선하는 팁

 
 
 


1. 왜 캘린더에서 할 일 추가가 필요할까요?

앱을 사용하다 보면, 선택한 날짜의 할 일을 확인하면서 바로 새로운 작업을 추가하고 싶을 때가 있어요.
기존 방식처럼 다른 화면으로 이동하거나, 할 일을 추가한 뒤 캘린더와 동기화하는 과정은 번거롭죠.

 

이 기능을 추가하면 이런 장점이 있어요:

  • 더 빠르고 편리한 작업 추가: 캘린더를 보면서 바로 할 일을 추가할 수 있어 시간 절약!
  • 자연스러운 워크플로우: 선택한 날짜에서 할 일을 추가하고 확인하는 모든 작업이 한 화면에서 이루어져요.
  • 사용자 경험 개선: 직관적이고 간단한 인터페이스로 사용자 만족도가 높아져요.

 
 
 


2. 할 일 추가 버튼 구현하기

그럼, 이제 직접 코드를 수정해볼게요. 아래 코드는 캘린더 모달 창 하단에 "할 일 추가" 버튼을 추가하고, 이를 눌렀을 때 새로운 할 일을 입력할 수 있는 다이얼로그를 띄우는 과정을 보여줍니다.
 
 


2.1 캘린더 모달 창에 버튼 추가하기

_showTasksForSelectedDay 메서드에 "할 일 추가" 버튼을 추가합니다.

void _showTasksForSelectedDay() {
  final selectedDateTasks = _getEventsForDay(_selectedDay ?? DateTime.now());

  showModalBottomSheet(
    context: context,
    isScrollControlled: true,
    builder: (context) {
      return Container(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            // 상단: 제목과 닫기 버튼
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  '${_selectedDay != null ? _selectedDay!.toLocal().toString().split(' ')[0] : '오늘'}의 할 일',
                  style: const TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                IconButton(
                  icon: const Icon(Icons.close),
                  onPressed: () => Navigator.of(context).pop(),
                ),
              ],
            ),
            const Divider(),

            // 중간: 할 일 목록
            selectedDateTasks.isEmpty
                ? const Center(
                    child: Text(
                      '할 일이 없습니다!',
                      style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                    ),
                  )
                : Expanded(
                    child: ListView.builder(
                      itemCount: selectedDateTasks.length,
                      itemBuilder: (context, index) {
                        final task = selectedDateTasks[index];
                        return Card(
                          elevation: 4.0,
                          margin: const EdgeInsets.symmetric(vertical: 8.0),
                          child: ListTile(
                            title: Text(
                              task,
                              style: const TextStyle(fontSize: 16),
                            ),
                            trailing: Row(
                              mainAxisSize: MainAxisSize.min,
                              children: [
                                IconButton(
                                  icon: const Icon(Icons.edit, color: Colors.blueAccent),
                                  onPressed: () {
                                    _showEditTodoDialog(
                                        context,
                                        _todoList.indexWhere(
                                            (item) => item['task'] == task));
                                  },
                                ),
                                IconButton(
                                  icon: const Icon(Icons.delete, color: Colors.redAccent),
                                  onPressed: () {
                                    setState(() {
                                      _deleteTodoItem(_todoList.indexWhere(
                                          (item) => item['task'] == task));
                                    });
                                    Navigator.of(context).pop();
                                    _showTasksForSelectedDay(); // 목록 갱신
                                  },
                                ),
                              ],
                            ),
                          ),
                        );
                      },
                    ),
                  ),

            // 하단: "할 일 추가" 버튼
            Padding(
              padding: const EdgeInsets.only(top: 16.0),
              child: ElevatedButton.icon(
                icon: const Icon(Icons.add),
                label: const Text('할 일 추가'),
                onPressed: () {
                  _showAddTodoDialog(context);
                  Navigator.of(context).pop();
                },
              ),
            ),
          ],
        ),
      );
    },
  );
}

 
 
 


2.2 새로운 할 일 추가 다이얼로그 구현

_showAddTodoDialog 메서드를 추가해, 사용자가 새로운 할 일을 입력할 수 있도록 합니다.

void _showAddTodoDialog(BuildContext context) {
  String newTask = "";

  showDialog(
    context: context,
    builder: (BuildContext context) {
      return AlertDialog(
        title: const Text("새로운 할 일 추가"),
        content: TextField(
          decoration: const InputDecoration(
            hintText: "할 일을 입력하세요",
          ),
          onChanged: (value) {
            newTask = value;
          },
        ),
        actions: [
          // 취소 버튼
          TextButton(
            onPressed: () {
              Navigator.of(context).pop(); // 다이얼로그 닫기
            },
            child: const Text("취소"),
          ),
          // 추가 버튼
          TextButton(
            onPressed: () {
              if (newTask.isNotEmpty) {
                // 할 일 리스트 추가하기
                _addTodoItem(newTask);

                // 다이얼로그 닫기 후 목록 갱신
                Navigator.of(context).pop();
                _showTasksForSelectedDay();
              }
            },
            child: const Text("추가"),
          ),
        ],
      );
    },
  );
}

 


2.3 기존 _addTodoItem 수정

_addTodoItem 메서드는 그대로 유지하며, 할 일을 추가한 뒤 로컬 저장소에 데이터를 저장하고 캘린더를 업데이트합니다.

void _addTodoItem(String task) {
  final today = DateTime.now(); // 현재 날짜
  final dateKey = _normalizeDate(_selectedDay ?? today); // 선택된 날짜 또는 현재 날짜

  setState(() {
    // 새로운 할 일 추가
    _todoList.add({
      'task': task,
      'isCompleted': false,
      'date': dateKey.toIso8601String(),
    });

    // 캘린더 이벤트 업데이트
    _calendarEvents[dateKey] = _calendarEvents[dateKey] ?? [];
    _calendarEvents[dateKey]!.add(task);
  });

  // 콘솔 출력 (디버깅용)
  print("할 일을 추가했어요! $_todoList");
  print("캘린더 이벤트: $_calendarEvents");

  // 데이터 저장
  _saveTodoList();
  _saveCalendarEvents();
}

 
 
 
 


3. UI/UX 개선 팁

  • 버튼 스타일링: 앱의 테마에 맞춰 버튼 색상과 텍스트를 조정해 UI를 더 깔끔하게 만드세요.
  • 모달 크기 조절: mainAxisSize: MainAxisSize.min을 사용해 화면에 필요한 만큼만 표시되도록 만듭니다.
  • 할 일 추가 후 실시간 업데이트: 새로운 할 일을 추가한 후 바로 캘린더와 목록이 갱신되도록 코드를 작성합니다.

 
 


결과

 
 
 


결론

이제 사용자는 캘린더에서 선택한 날짜의 할 일을 확인하고, 바로 새로운 할 일을 추가할 수 있게 되었습니다.
조금 더 편리하게 느껴지시죠? 😊 (그렇다고 해주세요 😁)
 
다음 글 부터는 상세 화면에 할 일 추가 버튼을 만들어서 생기는 문제점 에 대해 하나씩 해결해 나갈 예정입니다.
 
궁금한 점이나 더 추가하고 싶은 기능이 있다면 댓글로 남겨주세요.
함께 더 나은 앱을 만들어봅시다! 🚀

728x90
반응형