import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class SimpleFirestoreTodo extends StatefulWidget {
@override
State<SimpleFirestoreTodo> createState() => _SimpleFirestoreTodoState();
}
class _SimpleFirestoreTodoState extends State<SimpleFirestoreTodo> {
final TextEditingController _controller = TextEditingController();
void _addTodo() async {
final text = _controller.text.trim();
if (text.isEmpty) return;
await FirebaseFirestore.instance.collection('todos').add({'text': text});
_controller.clear();
}
void _deleteTodo(String id) async {
await FirebaseFirestore.instance.collection('todos').doc(id).delete();
}
void _editTodoDialog(String id, String currentText) {
final editController = TextEditingController(text: currentText);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Edit Todo'),
content: TextField(
controller: editController,
autofocus: true,
decoration: InputDecoration(hintText: 'Todo text'),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('Cancel'),
),
TextButton(
onPressed: () async {
final newText = editController.text.trim();
if (newText.isNotEmpty) {
await FirebaseFirestore.instance.collection('todos').doc(id).update({'text': newText});
}
Navigator.pop(context);
},
child: Text('Save'),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Simple Firestore Todo')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(hintText: 'Add Todo'),
onSubmitted: (_) => _addTodo(),
),
),
IconButton(
icon: Icon(Icons.add),
onPressed: _addTodo,
tooltip: 'Add todo',
),
],
),
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('todos').snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
return Center(child: Text('No todos yet'));
}
final docs = snapshot.data!.docs;
return ListView.builder(
itemCount: docs.length,
itemBuilder: (context, index) {
final doc = docs[index];
final todoText = doc['text'] ?? '';
return ListTile(
title: Text(todoText),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(Icons.edit),
tooltip: 'Edit todo',
onPressed: () => _editTodoDialog(doc.id, todoText),
),
IconButton(
icon: Icon(Icons.delete),
tooltip: 'Delete todo',
onPressed: () => _deleteTodo(doc.id),
),
],
),
);
},
);
},
),
),
],
),
),
);
}
}
This app uses Cloud Firestore to store todo items in a collection called 'todos'.
The _addTodo method adds a new document with the todo text. It clears the input after adding.
The _deleteTodo method deletes a document by its ID.
The _editTodoDialog shows a dialog with a TextField to update the todo text. On save, it updates the Firestore document.
The UI listens to live updates from Firestore using StreamBuilder and shows the list of todos. Each todo has Edit and Delete buttons.
This approach keeps the UI in sync with the database automatically.