mirror of
https://github.com/nisrulz/flutter-examples.git
synced 2025-11-09 04:58:58 +00:00
redo the app file structure and small cleanup in code
This commit is contained in:
247
firebase_todo_app/lib/AddTodo.dart
Normal file
247
firebase_todo_app/lib/AddTodo.dart
Normal file
@@ -0,0 +1,247 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:github.nisrulz.todo_app/Home.dart';
|
||||
|
||||
class AppTodo extends StatefulWidget {
|
||||
const AppTodo({super.key});
|
||||
|
||||
@override
|
||||
State<AppTodo> createState() => _AppTodoState();
|
||||
}
|
||||
|
||||
class _AppTodoState extends State<AppTodo> {
|
||||
String type = 'food';
|
||||
String SelectedCategory1 = 'important';
|
||||
TextEditingController titleController = TextEditingController();
|
||||
TextEditingController descriptionController = TextEditingController();
|
||||
|
||||
void saveTodoToFirebase() async {
|
||||
try {
|
||||
final User? user = FirebaseAuth.instance.currentUser;
|
||||
|
||||
if (user != null) {
|
||||
Map<String, dynamic> todoData = {
|
||||
'title': titleController.text,
|
||||
'description': descriptionController.text,
|
||||
'category': SelectedCategory1,
|
||||
'type': type,
|
||||
'createdAt': Timestamp.now(),
|
||||
'userId': user.uid,
|
||||
};
|
||||
|
||||
CollectionReference todos =
|
||||
FirebaseFirestore.instance.collection('todos');
|
||||
|
||||
await todos.add(todoData);
|
||||
|
||||
titleController.clear();
|
||||
descriptionController.clear();
|
||||
|
||||
Get.snackbar(
|
||||
"Added successfully",
|
||||
"You have added",
|
||||
backgroundColor: Colors.green,
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
duration: Duration(seconds: 3),
|
||||
);
|
||||
|
||||
Get.to(() => HomePage());
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error: $e');
|
||||
Get.snackbar(
|
||||
"Error",
|
||||
e.toString(),
|
||||
backgroundColor: Colors.red,
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
duration: Duration(seconds: 3),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Create Todo'),
|
||||
),
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[200],
|
||||
),
|
||||
padding: EdgeInsets.all(16.0),
|
||||
height: double.infinity,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Card(
|
||||
elevation: 4,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Title',
|
||||
style: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
TextField(
|
||||
controller: titleController,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Enter Title',
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Card(
|
||||
elevation: 4,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Task Type',
|
||||
style: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
ChoiceChip(
|
||||
label: Text('Important'),
|
||||
selected: SelectedCategory1 == 'important',
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
SelectedCategory1 = 'important';
|
||||
});
|
||||
},
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
ChoiceChip(
|
||||
label: Text('Planner'),
|
||||
selected: SelectedCategory1 == 'planner',
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
SelectedCategory1 = 'planner';
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Card(
|
||||
elevation: 4,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Description',
|
||||
style: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
TextFormField(
|
||||
controller: descriptionController,
|
||||
maxLines: 4,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Enter Description',
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Card(
|
||||
elevation: 4,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Category',
|
||||
style: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
children: [
|
||||
FilterChip(
|
||||
label: Text('Food'),
|
||||
selected: type == 'food',
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
type = 'food';
|
||||
});
|
||||
},
|
||||
),
|
||||
FilterChip(
|
||||
label: Text('Workout'),
|
||||
selected: type == 'workout',
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
type = 'workout';
|
||||
});
|
||||
},
|
||||
),
|
||||
FilterChip(
|
||||
label: Text('Run'),
|
||||
selected: type == 'run',
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
type = 'run';
|
||||
});
|
||||
},
|
||||
),
|
||||
FilterChip(
|
||||
label: Text('Design'),
|
||||
selected: type == 'design',
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
type = 'design';
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 50,
|
||||
),
|
||||
Center(
|
||||
child: FloatingActionButton(
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: saveTodoToFirebase,
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
47
firebase_todo_app/lib/Delete.dart
Normal file
47
firebase_todo_app/lib/Delete.dart
Normal file
@@ -0,0 +1,47 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class Delete extends StatelessWidget {
|
||||
final String taskId;
|
||||
|
||||
const Delete({required this.taskId, Key? key}) : super(key: key);
|
||||
|
||||
void _deleteTask() {
|
||||
final CollectionReference tasks =
|
||||
FirebaseFirestore.instance.collection('todos');
|
||||
|
||||
tasks.doc(taskId).delete().then((value) {
|
||||
Get.back();
|
||||
Get.snackbar(
|
||||
'Success',
|
||||
'Task updated successfully',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.green,
|
||||
colorText: Colors.white,
|
||||
);
|
||||
}).catchError((error) {
|
||||
print('Error deleting task in Firestore: $error');
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('Delete Task'),
|
||||
content: Text('Are you sure you want to delete this task?'),
|
||||
actions: <Widget>[
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
child: Text('Cancel'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: _deleteTask,
|
||||
child: Text('Delete'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
247
firebase_todo_app/lib/Edit.dart
Normal file
247
firebase_todo_app/lib/Edit.dart
Normal file
@@ -0,0 +1,247 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Edit extends StatefulWidget {
|
||||
final String taskId;
|
||||
final String initialTitle;
|
||||
final String initialDescription;
|
||||
final String initialTaskType;
|
||||
final String initialCategory;
|
||||
|
||||
const Edit({
|
||||
super.key,
|
||||
required this.taskId,
|
||||
required this.initialTitle,
|
||||
required this.initialDescription,
|
||||
required this.initialTaskType,
|
||||
required this.initialCategory,
|
||||
});
|
||||
|
||||
@override
|
||||
State<Edit> createState() => _EditState();
|
||||
}
|
||||
|
||||
class _EditState extends State<Edit> {
|
||||
late TextEditingController titleController;
|
||||
late TextEditingController descriptionController;
|
||||
String selectedTaskType = '';
|
||||
String selectedCategory = '';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
titleController = TextEditingController(text: widget.initialTitle);
|
||||
descriptionController =
|
||||
TextEditingController(text: widget.initialDescription);
|
||||
selectedTaskType = widget.initialTaskType;
|
||||
selectedCategory = widget.initialCategory;
|
||||
}
|
||||
|
||||
void updateTask() async {
|
||||
try {
|
||||
CollectionReference todos =
|
||||
FirebaseFirestore.instance.collection('todos');
|
||||
|
||||
await todos.doc(widget.taskId).update({
|
||||
'title': titleController.text,
|
||||
'description': descriptionController.text,
|
||||
'type': selectedTaskType,
|
||||
'category': selectedCategory,
|
||||
});
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Task updated successfully.'),
|
||||
),
|
||||
);
|
||||
|
||||
Navigator.of(context).pop();
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Failed to update the task: $e'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Edit Task'),
|
||||
),
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[200],
|
||||
),
|
||||
padding: EdgeInsets.all(16.0),
|
||||
height: double.infinity,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Card(
|
||||
elevation: 4,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Title',
|
||||
style: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
TextField(
|
||||
controller: titleController,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Enter Title',
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Card(
|
||||
elevation: 4,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Task Type',
|
||||
style: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
ChoiceChip(
|
||||
label: Text('Important'),
|
||||
selected: selectedTaskType == 'important',
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
selectedTaskType = 'important';
|
||||
});
|
||||
},
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
ChoiceChip(
|
||||
label: Text('Planner'),
|
||||
selected: selectedTaskType == 'planner',
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
selectedTaskType = 'planner';
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Card(
|
||||
elevation: 4,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Description',
|
||||
style: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
TextFormField(
|
||||
controller: descriptionController,
|
||||
maxLines: 4,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Enter Description',
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Card(
|
||||
elevation: 4,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Category',
|
||||
style: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
children: [
|
||||
FilterChip(
|
||||
label: Text('Food'),
|
||||
selected: selectedCategory == 'food',
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
selectedCategory = 'food';
|
||||
});
|
||||
},
|
||||
),
|
||||
FilterChip(
|
||||
label: Text('Workout'),
|
||||
selected: selectedCategory == 'workout',
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
selectedCategory = 'workout';
|
||||
});
|
||||
},
|
||||
),
|
||||
FilterChip(
|
||||
label: Text('Run'),
|
||||
selected: selectedCategory == 'run',
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
selectedCategory = 'run';
|
||||
});
|
||||
},
|
||||
),
|
||||
FilterChip(
|
||||
label: Text('Design'),
|
||||
selected: selectedCategory == 'design',
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
selectedCategory = 'design';
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 50,
|
||||
),
|
||||
Center(
|
||||
child: ElevatedButton(
|
||||
onPressed: updateTask,
|
||||
child: Text('Save Changes'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
151
firebase_todo_app/lib/Home.dart
Normal file
151
firebase_todo_app/lib/Home.dart
Normal file
@@ -0,0 +1,151 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:github.nisrulz.todo_app/AddTodo.dart';
|
||||
import 'package:github.nisrulz.todo_app/Delete.dart';
|
||||
import 'package:github.nisrulz.todo_app/Edit.dart';
|
||||
import 'package:github.nisrulz.todo_app/Signin.dart';
|
||||
|
||||
class HomePage extends StatelessWidget {
|
||||
final FirebaseAuth _auth = FirebaseAuth.instance;
|
||||
|
||||
HomePage({super.key});
|
||||
|
||||
Future<void> _signOut() async {
|
||||
try {
|
||||
await _auth.signOut();
|
||||
|
||||
Get.offAll(() => Signin());
|
||||
} catch (e) {
|
||||
print('Sign-out error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.logout),
|
||||
onPressed: () {
|
||||
_signOut();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () {
|
||||
Get.to(() => AppTodo());
|
||||
},
|
||||
child: Icon(Icons.add, color: Colors.white),
|
||||
),
|
||||
body: _buildTodoList(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTodoList() {
|
||||
final User? user = FirebaseAuth.instance.currentUser;
|
||||
|
||||
if (user == null) {
|
||||
return Center(
|
||||
child: Text('User not logged in.'),
|
||||
);
|
||||
}
|
||||
|
||||
return StreamBuilder<QuerySnapshot>(
|
||||
stream: FirebaseFirestore.instance
|
||||
.collection('todos')
|
||||
.where('userId', isEqualTo: user.uid)
|
||||
.snapshots(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Text('Error: ${snapshot.error}'),
|
||||
);
|
||||
}
|
||||
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
final List<Widget> todoWidgets = [];
|
||||
final todos = snapshot.data?.docs;
|
||||
|
||||
for (var todo in todos!) {
|
||||
final title = todo['title'];
|
||||
final description = todo['description'];
|
||||
final taskType = todo['type'];
|
||||
final category = todo['category'];
|
||||
|
||||
todoWidgets.add(
|
||||
Card(
|
||||
elevation: 4,
|
||||
margin: EdgeInsets.all(19.0),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(19.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Title: $title',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text('Description: $description'),
|
||||
Text('Task Type: $taskType'),
|
||||
Text('Category: $category'),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
Get.to(() => Edit(
|
||||
taskId: todo.id,
|
||||
initialTitle: todo['title'],
|
||||
initialDescription: todo['description'],
|
||||
initialTaskType: todo['type'],
|
||||
initialCategory: todo['category'],
|
||||
));
|
||||
},
|
||||
icon: Icon(Icons.edit),
|
||||
label: const Text(
|
||||
"Edit",
|
||||
style: TextStyle(color: Colors.orange),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
Get.to(() => Delete(taskId: todo.id));
|
||||
},
|
||||
icon: Icon(Icons.delete, color: Colors.red),
|
||||
label: const Text(
|
||||
"Delete",
|
||||
style: TextStyle(color: Colors.pink),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView(
|
||||
children: todoWidgets,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
142
firebase_todo_app/lib/Signin.dart
Normal file
142
firebase_todo_app/lib/Signin.dart
Normal file
@@ -0,0 +1,142 @@
|
||||
import 'package:firebase_auth/firebase_auth.dart' as firebase_auth;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:github.nisrulz.todo_app/Home.dart';
|
||||
import 'package:github.nisrulz.todo_app/Signup.dart';
|
||||
|
||||
class Signin extends StatefulWidget {
|
||||
const Signin({super.key});
|
||||
|
||||
@override
|
||||
State<Signin> createState() => _SigninState();
|
||||
}
|
||||
|
||||
class _SigninState extends State<Signin> {
|
||||
firebase_auth.FirebaseAuth firebaseauth = firebase_auth.FirebaseAuth.instance;
|
||||
final TextEditingController _emailcontroller = TextEditingController();
|
||||
final TextEditingController _passwordcontroller = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_emailcontroller.dispose();
|
||||
_passwordcontroller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _Signin() async {
|
||||
try {
|
||||
final String email = _emailcontroller.text;
|
||||
final String password = _passwordcontroller.text;
|
||||
|
||||
await firebaseauth.signInWithEmailAndPassword(
|
||||
email: email,
|
||||
password: password,
|
||||
);
|
||||
|
||||
Get.snackbar(
|
||||
"Sign In Success",
|
||||
"You have successfully signed in.",
|
||||
backgroundColor: Colors.green,
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
duration: Duration(seconds: 3),
|
||||
);
|
||||
|
||||
Get.to(() => HomePage());
|
||||
} catch (e) {
|
||||
Get.snackbar(
|
||||
"Sign In Error",
|
||||
e.toString(),
|
||||
backgroundColor: Colors.red,
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
duration: Duration(seconds: 3),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
child: Container(
|
||||
height: Get.size.height,
|
||||
width: Get.size.width,
|
||||
color: Colors.black,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
"Login ",
|
||||
style: TextStyle(
|
||||
color: Colors.green,
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const SizedBox(height: 20),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Container(
|
||||
width: Get.size.width - 60,
|
||||
height: 60,
|
||||
child: Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Center(
|
||||
child: TextField(
|
||||
controller: _emailcontroller,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Email',
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Container(
|
||||
width: Get.size.width - 60,
|
||||
height: 60,
|
||||
child: Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Center(
|
||||
child: TextField(
|
||||
controller: _passwordcontroller,
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Password',
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: _Signin,
|
||||
child: Text("Sign In"),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Get.to(() => Signup());
|
||||
},
|
||||
child: const Text(
|
||||
"Don't have an account? Sign Up",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
decoration: TextDecoration.underline,
|
||||
fontSize: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
141
firebase_todo_app/lib/Signup.dart
Normal file
141
firebase_todo_app/lib/Signup.dart
Normal file
@@ -0,0 +1,141 @@
|
||||
import 'package:firebase_auth/firebase_auth.dart' as firebase_auth;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:github.nisrulz.todo_app/Signin.dart';
|
||||
|
||||
class Signup extends StatefulWidget {
|
||||
const Signup({super.key});
|
||||
|
||||
@override
|
||||
State<Signup> createState() => _SignupState();
|
||||
}
|
||||
|
||||
class _SignupState extends State<Signup> {
|
||||
firebase_auth.FirebaseAuth firebaseauth = firebase_auth.FirebaseAuth.instance;
|
||||
final TextEditingController _emailcontroller = TextEditingController();
|
||||
final TextEditingController _passwordcontroller = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_emailcontroller.dispose();
|
||||
_passwordcontroller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _signUp() async {
|
||||
try {
|
||||
final String email = _emailcontroller.text;
|
||||
final String password = _passwordcontroller.text;
|
||||
|
||||
await firebaseauth.createUserWithEmailAndPassword(
|
||||
email: email,
|
||||
password: password,
|
||||
);
|
||||
|
||||
Get.snackbar(
|
||||
"Signed Up Success",
|
||||
"You have successfully signed up.",
|
||||
backgroundColor: Colors.green,
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
duration: Duration(seconds: 3),
|
||||
);
|
||||
|
||||
Get.to(() => const Signin());
|
||||
} catch (e) {
|
||||
Get.snackbar(
|
||||
"Sign Up Error",
|
||||
e.toString(),
|
||||
backgroundColor: Colors.red,
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
duration: Duration(seconds: 3),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
child: Container(
|
||||
height: Get.size.height,
|
||||
width: Get.size.width,
|
||||
color: Colors.black,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
"Sign Up",
|
||||
style: TextStyle(
|
||||
color: Colors.orange,
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const SizedBox(height: 20),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Container(
|
||||
width: Get.size.width - 60,
|
||||
height: 60,
|
||||
child: Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Center(
|
||||
child: TextField(
|
||||
controller: _emailcontroller,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Email',
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Container(
|
||||
width: Get.size.width - 60,
|
||||
height: 60,
|
||||
child: Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Center(
|
||||
child: TextField(
|
||||
controller: _passwordcontroller,
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Password',
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: _signUp,
|
||||
child: Text("Sign Up"),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Get.to(() => Signin());
|
||||
},
|
||||
child: const Text(
|
||||
"Already have an account? Login ",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
decoration: TextDecoration.underline,
|
||||
fontSize: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
80
firebase_todo_app/lib/firebase_options.dart
Normal file
80
firebase_todo_app/lib/firebase_options.dart
Normal file
@@ -0,0 +1,80 @@
|
||||
// File generated by FlutterFire CLI.
|
||||
// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members
|
||||
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||
import 'package:flutter/foundation.dart'
|
||||
show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||
|
||||
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// import 'firebase_options.dart';
|
||||
/// // ...
|
||||
/// await Firebase.initializeApp(
|
||||
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||
/// );
|
||||
/// ```
|
||||
class DefaultFirebaseOptions {
|
||||
static FirebaseOptions get currentPlatform {
|
||||
if (kIsWeb) {
|
||||
return web;
|
||||
}
|
||||
switch (defaultTargetPlatform) {
|
||||
case TargetPlatform.android:
|
||||
return android;
|
||||
case TargetPlatform.iOS:
|
||||
return ios;
|
||||
case TargetPlatform.macOS:
|
||||
return macos;
|
||||
case TargetPlatform.windows:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for windows - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.linux:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for linux - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
default:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions are not supported for this platform.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static const FirebaseOptions web = FirebaseOptions(
|
||||
apiKey: 'AIzaSyAZcBxEiSUSbrJdh2TqJfO4ySu_RRydpmk',
|
||||
appId: '1:845969639687:web:5e46819431e9bc03ba9da2',
|
||||
messagingSenderId: '845969639687',
|
||||
projectId: 'todoapp-cbd21',
|
||||
authDomain: 'todoapp-cbd21.firebaseapp.com',
|
||||
storageBucket: 'todoapp-cbd21.appspot.com',
|
||||
);
|
||||
|
||||
static const FirebaseOptions android = FirebaseOptions(
|
||||
apiKey: 'AIzaSyDJUJmEdax-zup4YIu4-Jc_E8VUaga-QC4',
|
||||
appId: '1:845969639687:android:fa41ba9dffeec1edba9da2',
|
||||
messagingSenderId: '845969639687',
|
||||
projectId: 'todoapp-cbd21',
|
||||
storageBucket: 'todoapp-cbd21.appspot.com',
|
||||
);
|
||||
|
||||
static const FirebaseOptions ios = FirebaseOptions(
|
||||
apiKey: 'AIzaSyBeRsZEhruSSbrrn-ayR5Nh5uuv-nTXeVs',
|
||||
appId: '1:845969639687:ios:3416ba56912c41d1ba9da2',
|
||||
messagingSenderId: '845969639687',
|
||||
projectId: 'todoapp-cbd21',
|
||||
storageBucket: 'todoapp-cbd21.appspot.com',
|
||||
iosBundleId: 'com.example.todoApp',
|
||||
);
|
||||
|
||||
static const FirebaseOptions macos = FirebaseOptions(
|
||||
apiKey: 'AIzaSyBeRsZEhruSSbrrn-ayR5Nh5uuv-nTXeVs',
|
||||
appId: '1:845969639687:ios:e5ec4ea82076de1cba9da2',
|
||||
messagingSenderId: '845969639687',
|
||||
projectId: 'todoapp-cbd21',
|
||||
storageBucket: 'todoapp-cbd21.appspot.com',
|
||||
iosBundleId: 'com.example.todoApp.RunnerTests',
|
||||
);
|
||||
}
|
||||
120
firebase_todo_app/lib/main.dart
Normal file
120
firebase_todo_app/lib/main.dart
Normal file
@@ -0,0 +1,120 @@
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get_navigation/src/root/get_material_app.dart';
|
||||
import 'package:github.nisrulz.todo_app/Signup.dart';
|
||||
|
||||
import 'firebase_options.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptions.currentPlatform,
|
||||
);
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetMaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Flutter Demo',
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: Signup(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
const MyHomePage({super.key, required this.title});
|
||||
|
||||
// This widget is the home page of your application. It is stateful, meaning
|
||||
// that it has a State object (defined below) that contains fields that affect
|
||||
// how it looks.
|
||||
|
||||
// This class is the configuration for the state. It holds the values (in this
|
||||
// case the title) provided by the parent (in this case the App widget) and
|
||||
// used by the build method of the State. Fields in a Widget subclass are
|
||||
// always marked "final".
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
State<MyHomePage> createState() => _MyHomePageState();
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
int _counter = 0;
|
||||
|
||||
void _incrementCounter() {
|
||||
setState(() {
|
||||
// This call to setState tells the Flutter framework that something has
|
||||
// changed in this State, which causes it to rerun the build method below
|
||||
// so that the display can reflect the updated values. If we changed
|
||||
// _counter without calling setState(), then the build method would not be
|
||||
// called again, and so nothing would appear to happen.
|
||||
_counter++;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// This method is rerun every time setState is called, for instance as done
|
||||
// by the _incrementCounter method above.
|
||||
//
|
||||
// The Flutter framework has been optimized to make rerunning build methods
|
||||
// fast, so that you can just rebuild anything that needs updating rather
|
||||
// than having to individually change instances of widgets.
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
// TRY THIS: Try changing the color here to a specific color (to
|
||||
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
|
||||
// change color while the other colors stay the same.
|
||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
// Here we take the value from the MyHomePage object that was created by
|
||||
// the App.build method, and use it to set our appbar title.
|
||||
title: Text(widget.title),
|
||||
),
|
||||
body: Center(
|
||||
// Center is a layout widget. It takes a single child and positions it
|
||||
// in the middle of the parent.
|
||||
child: Column(
|
||||
// Column is also a layout widget. It takes a list of children and
|
||||
// arranges them vertically. By default, it sizes itself to fit its
|
||||
// children horizontally, and tries to be as tall as its parent.
|
||||
//
|
||||
// Column has various properties to control how it sizes itself and
|
||||
// how it positions its children. Here we use mainAxisAlignment to
|
||||
// center the children vertically; the main axis here is the vertical
|
||||
// axis because Columns are vertical (the cross axis would be
|
||||
// horizontal).
|
||||
//
|
||||
// TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
|
||||
// action in the IDE, or press "p" in the console), to see the
|
||||
// wireframe for each widget.
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const Text(
|
||||
'You have pushed the button this many times:',
|
||||
),
|
||||
Text(
|
||||
'$_counter',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _incrementCounter,
|
||||
tooltip: 'Increment',
|
||||
child: const Icon(Icons.add),
|
||||
), // This trailing comma makes auto-formatting nicer for build methods.
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user