Content is user-generated and unverified.
// pubspec.yaml dependencies needed: // dependencies: // flutter: // sdk: flutter // firebase_core: ^2.24.2 // firebase_auth: ^4.15.3 // cloud_firestore: ^4.13.6 // main.dart import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:cloud_firestore/cloud_firestore.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 CRUD', theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: LoginPage(), ); } } class LoginPage extends StatefulWidget { @override _LoginPageState createState() => _LoginPageState(); } class _LoginPageState extends State<LoginPage> { final _formKey = GlobalKey<FormState>(); final _emailController = TextEditingController(); final _passwordController = TextEditingController(); bool _isLoading = false; Future<void> _login() async { if (!_formKey.currentState!.validate()) return; setState(() { _isLoading = true; }); try { await FirebaseAuth.instance.signInWithEmailAndPassword( email: _emailController.text.trim(), password: _passwordController.text.trim(), ); // Navigate to HomePage after successful login Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => HomePage()), ); } on FirebaseAuthException catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(e.message ?? 'Login failed'), backgroundColor: Colors.red, ), ); } finally { setState(() { _isLoading = false; }); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Login'), centerTitle: true, ), body: Padding( padding: EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.login, size: 100, color: Colors.blue, ), SizedBox(height: 30), TextFormField( controller: _emailController, decoration: InputDecoration( labelText: 'Email', prefixIcon: Icon(Icons.email), border: OutlineInputBorder(), ), validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your email'; } if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4} class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { final _titleController = TextEditingController(); final _descriptionController = TextEditingController(); final CollectionReference _items = FirebaseFirestore.instance.collection('items'); Future<void> _addItem() async { if (_titleController.text.isNotEmpty && _descriptionController.text.isNotEmpty) { await _items.add({ 'title': _titleController.text, 'description': _descriptionController.text, 'timestamp': FieldValue.serverTimestamp(), 'userId': FirebaseAuth.instance.currentUser!.uid, }); _titleController.clear(); _descriptionController.clear(); } } Future<void> _updateItem(String id, String title, String description) async { await _items.doc(id).update({ 'title': title, 'description': description, 'timestamp': FieldValue.serverTimestamp(), }); } Future<void> _deleteItem(String id) async { await _items.doc(id).delete(); } void _showAddDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Add New Item'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: _titleController, decoration: InputDecoration( labelText: 'Title', border: OutlineInputBorder(), ), ), SizedBox(height: 16), TextField( controller: _descriptionController, decoration: InputDecoration( labelText: 'Description', border: OutlineInputBorder(), ), maxLines: 3, ), ], ), actions: [ TextButton( onPressed: () { Navigator.pop(context); _titleController.clear(); _descriptionController.clear(); }, child: Text('Cancel'), ), ElevatedButton( onPressed: () { _addItem(); Navigator.pop(context); }, child: Text('Add'), ), ], ), ); } void _showEditDialog(String id, String currentTitle, String currentDescription) { _titleController.text = currentTitle; _descriptionController.text = currentDescription; showDialog( context: context, builder: (context) => AlertDialog( title: Text('Edit Item'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: _titleController, decoration: InputDecoration( labelText: 'Title', border: OutlineInputBorder(), ), ), SizedBox(height: 16), TextField( controller: _descriptionController, decoration: InputDecoration( labelText: 'Description', border: OutlineInputBorder(), ), maxLines: 3, ), ], ), actions: [ TextButton( onPressed: () { Navigator.pop(context); _titleController.clear(); _descriptionController.clear(); }, child: Text('Cancel'), ), ElevatedButton( onPressed: () { _updateItem(id, _titleController.text, _descriptionController.text); Navigator.pop(context); _titleController.clear(); _descriptionController.clear(); }, child: Text('Update'), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('CRUD Operations'), actions: [ IconButton( icon: Icon(Icons.logout), onPressed: () async { await FirebaseAuth.instance.signOut(); }, ), ], ), body: StreamBuilder<QuerySnapshot>( stream: _items .where('userId', isEqualTo: FirebaseAuth.instance.currentUser!.uid) .orderBy('timestamp', descending: true) .snapshots(), builder: (context, snapshot) { if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } final items = snapshot.data!.docs; if (items.isEmpty) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.inbox, size: 64, color: Colors.grey), SizedBox(height: 16), Text( 'No items yet', style: TextStyle(fontSize: 18, color: Colors.grey), ), SizedBox(height: 8), Text( 'Add your first item using the + button', style: TextStyle(color: Colors.grey), ), ], ), ); } return ListView.builder( padding: EdgeInsets.all(16), itemCount: items.length, itemBuilder: (context, index) { final item = items[index]; final data = item.data() as Map<String, dynamic>; return Card( elevation: 2, margin: EdgeInsets.only(bottom: 12), child: ListTile( contentPadding: EdgeInsets.all(16), title: Text( data['title'] ?? 'No Title', style: TextStyle(fontWeight: FontWeight.bold), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 8), Text(data['description'] ?? 'No Description'), SizedBox(height: 8), Text( 'Created: ${data['timestamp']?.toDate().toString().split('.')[0] ?? 'Unknown'}', style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ], ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.edit, color: Colors.blue), onPressed: () { _showEditDialog( item.id, data['title'] ?? '', data['description'] ?? '', ); }, ), IconButton( icon: Icon(Icons.delete, color: Colors.red), onPressed: () { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Delete Item'), content: Text('Are you sure you want to delete this item?'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('Cancel'), ), ElevatedButton( onPressed: () { _deleteItem(item.id); Navigator.pop(context); }, child: Text('Delete'), style: ElevatedButton.styleFrom( backgroundColor: Colors.red, ), ), ], ), ); }, ), ], ), ), ); }, ); }, ), floatingActionButton: FloatingActionButton( onPressed: _showAddDialog, child: Icon(Icons.add), ), ); } } ) .hasMatch(value)) { return 'Please enter a valid email'; } return null; }, ), SizedBox(height: 16), TextFormField( controller: _passwordController, decoration: InputDecoration( labelText: 'Password', prefixIcon: Icon(Icons.lock), border: OutlineInputBorder(), ), obscureText: true, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your password'; } if (value.length < 6) { return 'Password must be at least 6 characters'; } return null; }, ), SizedBox(height: 24), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _isLoading ? null : _login, child: _isLoading ? CircularProgressIndicator(color: Colors.white) : Text('Login'), style: ElevatedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 16), ), ), ), SizedBox(height: 16), TextButton( onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => RegisterPage()), ); }, child: Text('Don\'t have an account? Sign up'), ), ], ), ), ), ); } } class RegisterPage extends StatefulWidget { @override _RegisterPageState createState() => _RegisterPageState(); } class _RegisterPageState extends State<RegisterPage> { final _formKey = GlobalKey<FormState>(); final _nameController = TextEditingController(); final _emailController = TextEditingController(); final _passwordController = TextEditingController(); final _confirmPasswordController = TextEditingController(); bool _isLoading = false; Future<void> _register() async { if (!_formKey.currentState!.validate()) return; setState(() { _isLoading = true; }); try { // Create user with email and password UserCredential userCredential = await FirebaseAuth.instance.createUserWithEmailAndPassword( email: _emailController.text.trim(), password: _passwordController.text.trim(), ); // Update user profile with display name await userCredential.user!.updateDisplayName(_nameController.text.trim()); // Save user data to Firestore await FirebaseFirestore.instance .collection('users') .doc(userCredential.user!.uid) .set({ 'name': _nameController.text.trim(), 'email': _emailController.text.trim(), 'createdAt': FieldValue.serverTimestamp(), }); // Show success message ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Registration successful!'), backgroundColor: Colors.green, ), ); // Navigate to HomePage after successful registration Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => HomePage()), ); } on FirebaseAuthException catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(e.message ?? 'Registration failed'), backgroundColor: Colors.red, ), ); } finally { setState(() { _isLoading = false; }); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Sign Up'), centerTitle: true, ), body: Padding( padding: EdgeInsets.all(16.0), child: Form( key: _formKey, child: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox(height: 50), Icon( Icons.person_add, size: 100, color: Colors.blue, ), SizedBox(height: 30), TextFormField( controller: _nameController, decoration: InputDecoration( labelText: 'Full Name', prefixIcon: Icon(Icons.person), border: OutlineInputBorder(), ), validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your full name'; } if (value.length < 2) { return 'Name must be at least 2 characters'; } return null; }, ), SizedBox(height: 16), TextFormField( controller: _emailController, decoration: InputDecoration( labelText: 'Email', prefixIcon: Icon(Icons.email), border: OutlineInputBorder(), ), validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your email'; } if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4} class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { final _titleController = TextEditingController(); final _descriptionController = TextEditingController(); final CollectionReference _items = FirebaseFirestore.instance.collection('items'); Future<void> _addItem() async { if (_titleController.text.isNotEmpty && _descriptionController.text.isNotEmpty) { await _items.add({ 'title': _titleController.text, 'description': _descriptionController.text, 'timestamp': FieldValue.serverTimestamp(), 'userId': FirebaseAuth.instance.currentUser!.uid, }); _titleController.clear(); _descriptionController.clear(); } } Future<void> _updateItem(String id, String title, String description) async { await _items.doc(id).update({ 'title': title, 'description': description, 'timestamp': FieldValue.serverTimestamp(), }); } Future<void> _deleteItem(String id) async { await _items.doc(id).delete(); } void _showAddDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Add New Item'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: _titleController, decoration: InputDecoration( labelText: 'Title', border: OutlineInputBorder(), ), ), SizedBox(height: 16), TextField( controller: _descriptionController, decoration: InputDecoration( labelText: 'Description', border: OutlineInputBorder(), ), maxLines: 3, ), ], ), actions: [ TextButton( onPressed: () { Navigator.pop(context); _titleController.clear(); _descriptionController.clear(); }, child: Text('Cancel'), ), ElevatedButton( onPressed: () { _addItem(); Navigator.pop(context); }, child: Text('Add'), ), ], ), ); } void _showEditDialog(String id, String currentTitle, String currentDescription) { _titleController.text = currentTitle; _descriptionController.text = currentDescription; showDialog( context: context, builder: (context) => AlertDialog( title: Text('Edit Item'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: _titleController, decoration: InputDecoration( labelText: 'Title', border: OutlineInputBorder(), ), ), SizedBox(height: 16), TextField( controller: _descriptionController, decoration: InputDecoration( labelText: 'Description', border: OutlineInputBorder(), ), maxLines: 3, ), ], ), actions: [ TextButton( onPressed: () { Navigator.pop(context); _titleController.clear(); _descriptionController.clear(); }, child: Text('Cancel'), ), ElevatedButton( onPressed: () { _updateItem(id, _titleController.text, _descriptionController.text); Navigator.pop(context); _titleController.clear(); _descriptionController.clear(); }, child: Text('Update'), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('CRUD Operations'), actions: [ IconButton( icon: Icon(Icons.logout), onPressed: () async { await FirebaseAuth.instance.signOut(); }, ), ], ), body: StreamBuilder<QuerySnapshot>( stream: _items .where('userId', isEqualTo: FirebaseAuth.instance.currentUser!.uid) .orderBy('timestamp', descending: true) .snapshots(), builder: (context, snapshot) { if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } final items = snapshot.data!.docs; if (items.isEmpty) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.inbox, size: 64, color: Colors.grey), SizedBox(height: 16), Text( 'No items yet', style: TextStyle(fontSize: 18, color: Colors.grey), ), SizedBox(height: 8), Text( 'Add your first item using the + button', style: TextStyle(color: Colors.grey), ), ], ), ); } return ListView.builder( padding: EdgeInsets.all(16), itemCount: items.length, itemBuilder: (context, index) { final item = items[index]; final data = item.data() as Map<String, dynamic>; return Card( elevation: 2, margin: EdgeInsets.only(bottom: 12), child: ListTile( contentPadding: EdgeInsets.all(16), title: Text( data['title'] ?? 'No Title', style: TextStyle(fontWeight: FontWeight.bold), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 8), Text(data['description'] ?? 'No Description'), SizedBox(height: 8), Text( 'Created: ${data['timestamp']?.toDate().toString().split('.')[0] ?? 'Unknown'}', style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ], ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.edit, color: Colors.blue), onPressed: () { _showEditDialog( item.id, data['title'] ?? '', data['description'] ?? '', ); }, ), IconButton( icon: Icon(Icons.delete, color: Colors.red), onPressed: () { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Delete Item'), content: Text('Are you sure you want to delete this item?'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('Cancel'), ), ElevatedButton( onPressed: () { _deleteItem(item.id); Navigator.pop(context); }, child: Text('Delete'), style: ElevatedButton.styleFrom( backgroundColor: Colors.red, ), ), ], ), ); }, ), ], ), ), ); }, ); }, ), floatingActionButton: FloatingActionButton( onPressed: _showAddDialog, child: Icon(Icons.add), ), ); } } ) .hasMatch(value)) { return 'Please enter a valid email'; } return null; }, ), SizedBox(height: 16), TextFormField( controller: _passwordController, decoration: InputDecoration( labelText: 'Password', prefixIcon: Icon(Icons.lock), border: OutlineInputBorder(), ), obscureText: true, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your password'; } if (value.length < 6) { return 'Password must be at least 6 characters'; } return null; }, ), SizedBox(height: 16), TextFormField( controller: _confirmPasswordController, decoration: InputDecoration( labelText: 'Confirm Password', prefixIcon: Icon(Icons.lock_outline), border: OutlineInputBorder(), ), obscureText: true, validator: (value) { if (value == null || value.isEmpty) { return 'Please confirm your password'; } if (value != _passwordController.text) { return 'Passwords do not match'; } return null; }, ), SizedBox(height: 24), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _isLoading ? null : _register, child: _isLoading ? CircularProgressIndicator(color: Colors.white) : Text('Sign Up'), style: ElevatedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 16), ), ), ), SizedBox(height: 16), TextButton( onPressed: () { Navigator.pop(context); }, child: Text('Already have an account? Login'), ), ], ), ), ), ), ); } } class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { final _titleController = TextEditingController(); final _descriptionController = TextEditingController(); final CollectionReference _items = FirebaseFirestore.instance.collection('items'); Future<void> _addItem() async { if (_titleController.text.isNotEmpty && _descriptionController.text.isNotEmpty) { await _items.add({ 'title': _titleController.text, 'description': _descriptionController.text, 'timestamp': FieldValue.serverTimestamp(), 'userId': FirebaseAuth.instance.currentUser!.uid, }); _titleController.clear(); _descriptionController.clear(); } } Future<void> _updateItem(String id, String title, String description) async { await _items.doc(id).update({ 'title': title, 'description': description, 'timestamp': FieldValue.serverTimestamp(), }); } Future<void> _deleteItem(String id) async { await _items.doc(id).delete(); } void _showAddDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Add New Item'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: _titleController, decoration: InputDecoration( labelText: 'Title', border: OutlineInputBorder(), ), ), SizedBox(height: 16), TextField( controller: _descriptionController, decoration: InputDecoration( labelText: 'Description', border: OutlineInputBorder(), ), maxLines: 3, ), ], ), actions: [ TextButton( onPressed: () { Navigator.pop(context); _titleController.clear(); _descriptionController.clear(); }, child: Text('Cancel'), ), ElevatedButton( onPressed: () { _addItem(); Navigator.pop(context); }, child: Text('Add'), ), ], ), ); } void _showEditDialog(String id, String currentTitle, String currentDescription) { _titleController.text = currentTitle; _descriptionController.text = currentDescription; showDialog( context: context, builder: (context) => AlertDialog( title: Text('Edit Item'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: _titleController, decoration: InputDecoration( labelText: 'Title', border: OutlineInputBorder(), ), ), SizedBox(height: 16), TextField( controller: _descriptionController, decoration: InputDecoration( labelText: 'Description', border: OutlineInputBorder(), ), maxLines: 3, ), ], ), actions: [ TextButton( onPressed: () { Navigator.pop(context); _titleController.clear(); _descriptionController.clear(); }, child: Text('Cancel'), ), ElevatedButton( onPressed: () { _updateItem(id, _titleController.text, _descriptionController.text); Navigator.pop(context); _titleController.clear(); _descriptionController.clear(); }, child: Text('Update'), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('CRUD Operations'), actions: [ IconButton( icon: Icon(Icons.logout), onPressed: () async { await FirebaseAuth.instance.signOut(); }, ), ], ), body: StreamBuilder<QuerySnapshot>( stream: _items .where('userId', isEqualTo: FirebaseAuth.instance.currentUser!.uid) .orderBy('timestamp', descending: true) .snapshots(), builder: (context, snapshot) { if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } final items = snapshot.data!.docs; if (items.isEmpty) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.inbox, size: 64, color: Colors.grey), SizedBox(height: 16), Text( 'No items yet', style: TextStyle(fontSize: 18, color: Colors.grey), ), SizedBox(height: 8), Text( 'Add your first item using the + button', style: TextStyle(color: Colors.grey), ), ], ), ); } return ListView.builder( padding: EdgeInsets.all(16), itemCount: items.length, itemBuilder: (context, index) { final item = items[index]; final data = item.data() as Map<String, dynamic>; return Card( elevation: 2, margin: EdgeInsets.only(bottom: 12), child: ListTile( contentPadding: EdgeInsets.all(16), title: Text( data['title'] ?? 'No Title', style: TextStyle(fontWeight: FontWeight.bold), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 8), Text(data['description'] ?? 'No Description'), SizedBox(height: 8), Text( 'Created: ${data['timestamp']?.toDate().toString().split('.')[0] ?? 'Unknown'}', style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ], ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.edit, color: Colors.blue), onPressed: () { _showEditDialog( item.id, data['title'] ?? '', data['description'] ?? '', ); }, ), IconButton( icon: Icon(Icons.delete, color: Colors.red), onPressed: () { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Delete Item'), content: Text('Are you sure you want to delete this item?'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('Cancel'), ), ElevatedButton( onPressed: () { _deleteItem(item.id); Navigator.pop(context); }, child: Text('Delete'), style: ElevatedButton.styleFrom( backgroundColor: Colors.red, ), ), ], ), ); }, ), ], ), ), ); }, ); }, ), floatingActionButton: FloatingActionButton( onPressed: _showAddDialog, child: Icon(Icons.add), ), ); } }
Content is user-generated and unverified.
    Flutter Firebase Auth & CRUD App | Claude