본문 바로가기

[Flutter]drift로 todo list 만들기 예제 - 2탄(with drift, SQLite)

ironwhale 2022. 3. 5.

Flutter로 todo list 만들기 1탄에 이어 2탄도 이어 가겠습니다. 

1탄을 못보신 분은 아래 링크로 가시면 됩니다. 

https://jh-industry.tistory.com/52

 

[Flutter] todo list 만들기 예제 - 1탄(with drift, SQLite)

시작하면서... 이전에 Moor를 이용한 SQLite CR 포스팅을 한적이 있습니다. 이후 Update와 Delete 부분에 대한 포스팅을 한다고 했는데 아직까지 못했네요 지금은 Moor가 drift로 이름이 바뀐거 같더군요

jh-industry.tistory.com

 

완성된 화면

 

어플 구현 영상

main.dart 

아래 전체 코드에는 드리프트(drift) 사용법과는 관계 없는 코드도 있습니다만 우선 전체적인 부분적인 코드를 발췌하기 보다는 전체 코드를 보는것이 더 이해하시기 쉬울거 같아 전체 코드도 적었습니다.

 

드리프트(drift) 사용에 필요한 코드

일단 어디서든 접근할수 있도록 database.dart의 MyDatabase 자료형의 database를 전역변수로 설정하고 

메인 함수 실행 시 database에 MyDatabase 인스턴스를 할당합니다. <- 사실 이렇게 설명하는 것이 맞는지는 잘 모르겠지만, 어디서든 database 인스턴스를 사용하여 CRUD를 구현하기 위한 첫단계라고 이해하였습니다.

late MyDatabase database;

void main() {
  database = MyDatabase();
  logger.d("start my App!!");
  runApp(MyApp());
}

전체 코드 

import 'package:beamer/beamer.dart';
import 'package:firebasetrain/router/home_location.dart';
import 'package:firebasetrain/util/logger.dart';
import 'package:flutter/material.dart';
import 'drift/database.dart';

final _routerDelegate = BeamerDelegate(
    guards: [
      BeamGuard(
          beamToNamed: (_, __) => '/start',
          pathPatterns: ['/'],
          check: (context, location) => true)
    ],
    locationBuilder: BeamerLocationBuilder(
        beamLocations: [HomeLocation(), StartLocation()]));



late MyDatabase database;

void main() {
  database = MyDatabase();
  logger.d("start my App!!");
  runApp(MyApp());
}

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
        theme: ThemeData(
            primaryColor: Colors.green,
            primarySwatch: Colors.green,
            textTheme: TextTheme(button: TextStyle(color: Colors.black87)),
            textButtonTheme: TextButtonThemeData(
                style: TextButton.styleFrom(
                    primary: Colors.white,
                    minimumSize: Size(48, 48),
                    backgroundColor: Colors.green))),
        routeInformationParser: BeamerParser(),
        routerDelegate: _routerDelegate);
  }
}

SQLite에 입력해보자

역시 전체 코드에는 드리프트(drift) 사용법과는 관계 없는 코드도 있고, 아마 입력창과 보여주는 창을 왔다갔다 해주는 부분의 코드도 생략되었습니다. 혹시 요청시 전체 코드를 공개하도록 하겠습니다. 

 

저장 되는 기능 부분

database.dart에 구현된 addTodos를 사용하는 부분입니다.

입력하는 자료형은 자동으로 생성된 TodosCompanion이며 Value로 감싸서 입력하시면 됩니다. 

TextButton(
    onPressed: () async {
      if (_formKey.currentState != null) {
        bool passed = _formKey.currentState!.validate();
        if (passed) {
          await database.addTodos(TodosCompanion(
              title: Value(_titleController.text),
              content: Value(_contentController.text)));
          logger.d("input DBs");
          logger.d(await database.allTodoEntries);
          SnackBar snackbar =
              SnackBar(content: Text("저장 되었습니다."));
          ScaffoldMessenger.of(context).showSnackBar(snackbar);
        }
      }
    },
    child: Text("저장", style: Theme.of(context).textTheme.button)),

전체코드 

import 'package:drift/drift.dart' hide Column;
import 'package:firebasetrain/const/common_size.dart';
import 'package:firebasetrain/drift/database.dart';
import 'package:firebasetrain/main.dart';
import 'package:firebasetrain/util/logger.dart';
import 'package:flutter/material.dart';

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

  final borderside =
      OutlineInputBorder(borderSide: BorderSide(color: Colors.grey));

  TextEditingController _titleController = TextEditingController();

  TextEditingController _contentController = TextEditingController();

  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("할일 입력하기"),
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: common_padding_size),
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              const SizedBox(height: 10),
              TextFormField(
                decoration:
                    InputDecoration(hintText: "제목을 입력해주세요", border: borderside),
                controller: _titleController,
                validator: (title) {
                  if (title != null &&
                      title.length >= 6 &&
                      title.length <= 32) {
                    return null;
                  } else {
                    return "6자에서 32자를 입력해주세요";
                  }
                },
              ),
              const SizedBox(height: 20),
              TextFormField(
                decoration:
                    InputDecoration(hintText: "할일을 입력해주세요", border: borderside),
                maxLines: 10,
                controller: _contentController,
                validator: (context) {
                  return null;
                },
              ),
              const SizedBox(height: 20),
              TextButton(
                  onPressed: () async {
                    if (_formKey.currentState != null) {
                      bool passed = _formKey.currentState!.validate();
                      if (passed) {
                        await database.addTodos(TodosCompanion(
                            title: Value(_titleController.text),
                            content: Value(_contentController.text)));
                        logger.d("input DBs");
                        logger.d(await database.allTodoEntries);
                        SnackBar snackbar =
                            SnackBar(content: Text("저장 되었습니다."));
                        ScaffoldMessenger.of(context).showSnackBar(snackbar);
                      }
                    }
                  },
                  child: Text("저장", style: Theme.of(context).textTheme.button)),
            ],
          ),
        ),
      ),
    );
  }
}

 


읽어오기와 삭제하기

FutureBuilder와 리스트뷰를 통해 간단하게 구현해 보았습니다.

 

database.dart 파일에 구현된 읽어오기, 삭제 부분

Future<List<Todo>> get allTodoEntries => select(todos).get();

Future delTodo(data) { return delete(todos).delete(data); }

 

읽어오기 

읽어오기 함수의 리턴 값이 future이기 때문에 FutureBuilder를 사용하였고 FutureBuilder의 future 부분에

future: database.allTodoEntries 이렇게 입력하였습니다. 

불러온 데이터를 리스트뷰 형태로 구현하였습니다. 

 

삭제하기

각 리스트 별로 버튼을 만들어서 구현하였고, 단순히 data[index]형태로 함수에 집어 넣으면 삭제가 됩니다.

onPressed: () {
  database.delTodo(data[index]);
  logger.d("input del button");
  setState(() {});
},

 

전체코드

import 'package:firebasetrain/drift/database.dart';
import 'package:firebasetrain/main.dart';
import 'package:firebasetrain/util/logger.dart';
import 'package:flutter/material.dart';

class TodoList extends StatefulWidget {
  const TodoList({Key? key}) : super(key: key);

  @override
  State<TodoList> createState() => _TodoListState();
}

class _TodoListState extends State<TodoList> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("할일 보기")),
      body: FutureBuilder<List<Todo>>(
          future: database.allTodoEntries,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              final data = snapshot.data;
              return ListView.builder(
                  itemCount: data!.length,
                  itemBuilder: (_, index) {
                    return Card(
                      child: ListTile(
                          title: Text(data[index].title),
                          subtitle: Text(data[index].content),
                          trailing: IconButton(
                            icon: Icon(Icons.delete),
                            onPressed: () {
                              database.delTodo(data[index]);
                              logger.d("input del button");
                              setState(() {});
                            },
                          )),
                    );
                  });
            } else {
              return Container();
            }
          }),
    );
  }
}

 


간단한 예제로 SQLite를 활용한 플러터 어플 만들기 예제 였습니다. 

 

 

 

댓글