반응형

 

Firestore를 사용하여 To-Do 앱을 만드는 방법을 설명하겠습니다. 이 예제에서는 Firebase Firestore를 사용하여 할 일 데이터를 저장하고, 읽고, 업데이트하고, 삭제하는 기능을 구현합니다.

 

1. firebase 내 데이터베이스 만들기

위와 같이 firestore 를 생성해줍니다. 

 

1. 프로젝트 설정

 

pubspec.yaml 파일 업데이트

 

최신 Firebase 패키지를 pubspec.yaml 파일에 추가합니다.

dependencies:
  flutter:
    sdk: flutter
  firebase_core: 
  firebase_auth: 
  cloud_firestore:

2. Firebase 설정

 

google-services.json 파일을 다운로드하여 android/app 디렉토리에 복사합니다. Firebase 콘솔에서 프로젝트를 설정하고 앱을 등록한 후 이 파일을 받을 수 있습니다.

 

android/build.gradle 파일 업데이트

buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:8.0.0'
        classpath 'com.google.gms:google-services:4.4.2'
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

android/app/build.gradle 파일 업데이트

apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'

android {
    compileSdkVersion 34

    defaultConfig {
        applicationId "com.example.flutter_todo"
        minSdkVersion 21
        targetSdkVersion 34
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation platform('com.google.firebase:firebase-bom:32.2.2')
}

apply plugin: 'com.google.gms.google-services'

 

3. Firebase 초기화

 

main.dart

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'screens/todo_list_screen.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Firebase Todo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: TodoListScreen(),
    );
  }
}

 

4. Firestore 데이터 모델

 

models/todo.dart

class Todo {
  final String id;
  final String title;
  final bool isDone;

  Todo({
    required this.id,
    required this.title,
    this.isDone = false,
  });

  factory Todo.fromMap(Map<String, dynamic> data, String documentId) {
    return Todo(
      id: documentId,
      title: data['title'] ?? '',
      isDone: data['isDone'] ?? false,
    );
  }

  Map<String, dynamic> toMap() {
    return {
      'title': title,
      'isDone': isDone,
    };
  }
}

5. Firestore 서비스

 

services/firestore_service.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import '../models/todo.dart';

class FirestoreService {
  final FirebaseFirestore _db = FirebaseFirestore.instance;

  Stream<List<Todo>> getTodos() {
    return _db.collection('todos').snapshots().map((snapshot) =>
        snapshot.docs.map((doc) => Todo.fromMap(doc.data(), doc.id)).toList());
  }

  Future<void> addTodo(Todo todo) {
    return _db.collection('todos').add(todo.toMap());
  }

  Future<void> updateTodo(Todo todo) {
    return _db.collection('todos').doc(todo.id).update(todo.toMap());
  }

  Future<void> deleteTodo(String id) {
    return _db.collection('todos').doc(id).delete();
  }
}

6. 프로바이더 설정

 

providers/todo_provider.dart

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import '../models/todo.dart';
import '../services/firestore_service.dart';

class TodoProvider with ChangeNotifier {
  final FirestoreService _firestoreService = FirestoreService();

  late Stream<List<Todo>> _todos;
  Stream<List<Todo>> get todos => _todos;

  TodoProvider() {
    _todos = _firestoreService.getTodos();
  }

  Future<void> addTodo(Todo todo) async {
    await _firestoreService.addTodo(todo);
  }

  Future<void> updateTodo(Todo todo) async {
    await _firestoreService.updateTodo(todo);
  }

  Future<void> deleteTodo(String id) async {
    await _firestoreService.deleteTodo(id);
  }
}

7. UI 작성

 

screens/todo_list_screen.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/todo.dart';
import '../providers/todo_provider.dart';
import 'edit_todo_screen.dart';

class TodoListScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('To-Do List'),
      ),
      body: StreamBuilder<List<Todo>>(
        stream: Provider.of<TodoProvider>(context).todos,
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return Center(child: CircularProgressIndicator());
          }
          final todos = snapshot.data!;
          return ListView.builder(
            itemCount: todos.length,
            itemBuilder: (ctx, i) => ListTile(
              title: Text(todos[i].title),
              trailing: Checkbox(
                value: todos[i].isDone,
                onChanged: (value) {
                  Provider.of<TodoProvider>(context, listen: false).updateTodo(
                    Todo(
                      id: todos[i].id,
                      title: todos[i].title,
                      isDone: value!,
                    ),
                  );
                },
              ),
              onLongPress: () {
                Provider.of<TodoProvider>(context, listen: false)
                    .deleteTodo(todos[i].id);
              },
              onTap: () {
                Navigator.of(context).push(
                  MaterialPageRoute(
                    builder: (context) => EditTodoScreen(todo: todos[i]),
                  ),
                );
              },
            ),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          showDialog(
            context: context,
            builder: (ctx) {
              TextEditingController controller = TextEditingController();
              return AlertDialog(
                title: Text('Add Todo'),
                content: TextField(
                  controller: controller,
                  decoration: InputDecoration(labelText: 'Title'),
                ),
                actions: [
                  TextButton(
                    onPressed: () {
                      if (controller.text.isNotEmpty) {
                        final newTodo = Todo(
                          id: '',
                          title: controller.text,
                        );
                        Provider.of<TodoProvider>(context, listen: false)
                            .addTodo(newTodo);
                        Navigator.of(ctx).pop();
                      }
                    },
                    child: Text('Add'),
                  ),
                ],
              );
            },
          );
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

screens/edit_todo_screen.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/todo.dart';
import '../providers/todo_provider.dart';

class EditTodoScreen extends StatelessWidget {
  final Todo todo;

  EditTodoScreen({required this.todo});

  @override
  Widget build(BuildContext context) {
    TextEditingController titleController = TextEditingController(text: todo.title);

    return Scaffold(
      appBar: AppBar(
        title: Text('Edit Todo'),
      ),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: titleController,
              decoration: InputDecoration(labelText: 'Title'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                if (titleController.text.isNotEmpty) {
                  final updatedTodo = Todo(
                    id: todo.id,
                    title: titleController.text,
                    isDone: todo.isDone,
                  );
                  Provider.of<TodoProvider>(context, listen: false)
                      .updateTodo(updatedTodo);
                  Navigator.of(context).pop();
                }
              },
              child: Text('Update'),
            ),
          ],
        ),
      ),
    );
  }
}

요약

 

1. Firestore 데이터 모델(Todo)을 정의합니다.

2. Firestore 서비스(FirestoreService)를 작성하여 Firestore와 상호작용합니다.

3. 프로바이더(TodoProvider)를 작성하여 상태 관리를 합니다.

4. UI를 작성하여 할 일 목록을 표시하고 추가, 수정, 삭제 기능을 구현합니다.

5. Firebase를 초기화하고 앱을 실행합니다.

 

이제 Firestore를 사용하여 할 일 데이터를 관리하는 간단한 To-Do 앱이 완성되었습니다. 필요에 따라 추가 기능을 구현하거나 UI를 개선할 수 있습니다.

반응형

+ Recent posts