본문 바로가기

Flutter/10 app Todo with GetX

[Flutter] App Todo(with Getx) - 5단계 todo 편집 refactoring

상태관리에서 배운 Getx를 이용하여 todo 어플을 만들어 보려고 합니다.

이전 버전은 provider 로 상태관리하는 todo 어플을 만들었다.

오늘은 특정 리스트 편집 기능을 refactoring 해보겠습니다.

개발환경 : 윈도우11, 안드로이드 스튜디오, flutter 2.10.3

소스코드 위치 - Release 06_edit_refactoring · mike-bskim/todo_getx · GitHub

 

Release 06_edit_refactoring · mike-bskim/todo_getx

 

github.com

 

 

리스트 편집 기능의 상태관리를 StatefulWidget 에서 GetxController 로 변경해보겠습니다.

 

오늘의 프로젝트 주요파일은 아래와 같다.

./bindings/todo_binding.dart

./controller/todo_list_controller.dart

./screens/todos_screen.dart

./controller/todo_focus_controller.dart

 

 

./bindings/todo_binding.dart

 

import 'package:get/get.dart';
import '../controller/todo_focus_controller.dart';
import '../controller/todo_list_controller.dart';

class TodoBinding extends Bindings {
  @override
  void dependencies() {
    // dependency injection
    Get.put<TodosList>(TodosList());
    Get.put<TodosFilter>(TodosFilter());
    Get.put<TodosSearch>(TodosSearch());
    // 상기 3개의 controller 는 ActiveCount/FilteredTodos 에 영향을 주기때문에
    // ActiveCount/FilteredTodos 보다 위에/먼저 선언되어야 한다
    Get.put<ActiveCount>(ActiveCount());
    Get.put<FilteredTodos>(FilteredTodos());
    // put 으로 injection 하면 편집시 모든 텍스트가 변경된다. 그래서 create 로 해야 함
    Get.create<TodoFocusController>(() => TodoFocusController());
  }
}

 

./controller/todo_list_controller.dart - searchWordController 추가, 없어도 기능엔 문제가 없음

 

class TodosSearch extends GetxController {
  RxString searchWord = ''.obs;
  late TextEditingController searchWordController;

  static TodosSearch get to => Get.find();
  @override
  void onInit() {
    searchWordController = TextEditingController();
    super.onInit();
  }
  @override
  void onClose() {
    searchWordController.dispose();
    super.onClose();
  }
}

 

./screens/todos_screen.dart

 

class SearchAndFilterTodo extends StatelessWidget {
  const SearchAndFilterTodo({Key? key}) : super(key: key);

  // final debounce = Debounce(milliseconds: 1000);
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextFormField(
// 신규 추가한 controller 를 여기에 추가
          controller: TodosSearch.to.searchWordController,
          decoration: const InputDecoration(
            labelText: 'Search todos',
            border: InputBorder.none,
            filled: true,
            prefixIcon: Icon(Icons.search),
          ),

 

class TodoItem extends StatelessWidget {
  final Todo todo;

  const TodoItem({Key? key, required this.todo}) : super(key: key);

  @override
  Widget build(BuildContext context) {
// GetBuilder 추가함
    return GetBuilder<TodoFocusController>(
      builder: (controller) {
        return Padding(
          padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 1),
          child: Focus(
            focusNode: controller.itemFocusNode,
            onFocusChange: (value) {
              // if value is true, it get the focus
              if (value) {
                controller.textEditingController.text = todo.desc;
                debugPrint('got the focus: "${todo.desc}"');
              } else {
                TodosList.to.editTodo(
                  id: todo.id,
                  desc: controller.textEditingController.text,
                );
                debugPrint('lost the focus: "${todo.desc}"');
              }
            },
            child: ListTile(
              onTap: () {
                debugPrint('click for editing~~');
                controller.requestFocus();
              },
              leading: Checkbox(
                value: todo.completed,
                onChanged: (bool? checked) {
                  debugPrint('clicked toggle button~~');
                  TodosList.to.toggleTodo(id: todo.id);
                },
              ),
              title: controller.itemFocusNode.hasFocus
                  ? TextField(
                      controller: controller.textEditingController,
                      autofocus: true,
                      focusNode: controller.textFieldFocusNode,
                    )
                  : Text(todo.desc),
            ),
          ),
        );
      },
    );
  }
}

 

./controller/todo_focus_controller.dart

 

import 'package:flutter/material.dart';
import 'package:get/get.dart';

class TodoFocusController extends GetxController {
  late FocusNode itemFocusNode;
  late FocusNode textFieldFocusNode;
  late TextEditingController textEditingController;

  static TodoFocusController get to => Get.find();

  @override
  void onInit() {
    itemFocusNode = FocusNode();
    textFieldFocusNode = FocusNode();
    textEditingController = TextEditingController();
    super.onInit();
  }

  void requestFocus() {
    // 이건 focus 취득 및 타이틀을 텍스트 또는 텍스트필드로 변환하는 기능
    itemFocusNode.requestFocus();
    // 아래는 수정시, 텍스트필드의 autofocus 및 키보드 자동로딩용
    // 없어도 동작에는 문제가 없음, 약간 불편한 화면처리 정도임
    textFieldFocusNode.requestFocus();
    update();
  }

  @override
  void onClose() {
    itemFocusNode.dispose();
    textFieldFocusNode.dispose();
    textEditingController.dispose();
    super.onClose();
  }
}

 

 

 

 

 

[참고자료] 헤비프랜

- https://www.youtube.com/watch?v=HZJsKlN-kmc&list=PLGJ958IePUyDQwYbPcz-5W9o4p1__20V0&index=5