Step 1
Register app
android\app\build.gradle
defaultConfig {
// Copy this id from your application
applicationId = "com.example.tourismapp"
}
Step 2
download google-services.json and place it on android\app\
Step 3
Add Firebase SDK
android\settings.gradle
plugins {
// Add the dependency for the Google services Gradle plugin
id 'com.google.gms.google-services' version '4.4.2' apply false
}
android\app\build.gradle
plugins {
// Add the Google services Gradle plugin
id 'com.google.gms.google-services'
...
}
Step 4
Continue to console
Select Authentication
Setup Sign-in method
Enable Email/Password
Install the following packages:
flutter pub add cloud_firestore
flutter pub add firebase_auth
flutter pub add firebase_core
Verify pubspec.yaml file
dependencies:
flutter:
sdk: flutter
cloud_firestore: ^5.5.0
firebase_auth: ^5.3.4
firebase_core: ^3.9.0
*note firebase version sometimes gives error so ensure to check documentation in case you encounter some issues
Select Firestore & create database
Select start in test mode
Denying access to database
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
Allow access to database
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
import 'package:firebase_core/firebase_core.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: FirebaseOptions(
apiKey: "AIzaSy...36J-nfxE..DwF-b..usR8",
appId: "1:503..512:android:a7d9..1cc599e5f5",
messagingSenderId: "503...512",
projectId: "tou...asus"));
runApp(const MyApp());
}
firebaseOptions can be found on your google-services.json
apiKey -> api_key current_key
appId -> mobilesdk_app_id
messagingSenderId-> project_number
projectId -> project_id
Update registration_page.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class _RegistrationPageState extends State<RegistrationPage> {
final TextEditingController _pass = TextEditingController();
final TextEditingController _cpass = TextEditingController();
final TextEditingController _email = TextEditingController();
final TextEditingController _fullname = TextEditingController();
final TextEditingController _birthdate = TextEditingController();
Future registerUser() async {
if (_pass.text == _cpass.text) {
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: _email.text.trim(),
password: _pass.text.trim(),
);
addUserDetails();
}
}
Future addUserDetails() async {
await FirebaseFirestore.instance.collection('users').add({
'email': _email.text.trim(),
'fullname': _fullname.text.trim(),
'birthdate': _birthdate.text.trim(),
}).then((value) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('User registered successfully!'),
),
);
}).catchError((error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to register user: $error'),
),
);
});
}
ElevatedButton(
onPressed: () {
// Handle registration logic here
registerUser();
},
child: Text('Register'),
),
TextButton(
onPressed: () {
// Handle login logic here
},
child: Text('Already have an account? Login'),
),
TextButton(
onPressed: () {
// Handle back navigation logic here
Navigator.pop(context);
},
child: Text('Back', style: TextStyle(color: Colors.red)),
),
login_page.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:tourismapp/main.dart';
import 'package:tourismapp/registration_page.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
TextEditingController _email = TextEditingController();
TextEditingController _pass = TextEditingController();
Future signIn() async {
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _email.text.trim(),
password: _pass.text.trim(),
);
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => MyHome(),
));
} on FirebaseAuthException catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(e.code),
backgroundColor: Colors.red,
),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('An unexpected error occurred. Please try again.'),
backgroundColor: Colors.red,
),
);
}
}
@override
void dispose() {
_email.dispose();
_pass.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Container(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.network(
'https://cdn.dribbble.com/userupload/24923465/file/original-51ddb71cc2869cb7affa15794700afc9.jpg'),
TextField(
controller: _email,
decoration: const InputDecoration(
labelText: 'Email',
border: OutlineInputBorder(),
),
),
SizedBox(height: 20),
TextField(
controller: _pass,
decoration: const InputDecoration(
labelText: 'Password',
border: OutlineInputBorder(),
),
obscureText: true,
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
signIn();
},
child: const Text('Login'),
),
TextButton(
onPressed: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) =>
RegistrationPage()), // Replace with your Registration widget
);
},
child: Text('Don\'t have an account? SignUp'),
),
TextButton(
onPressed: () {
//Navigator.pop(context);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) =>
LoginPage()), // Replace with your SignUp widget
);
},
child: Text('Back', style: TextStyle(color: Colors.red)),
),
],
),
),
);
}
}
Main.dart
Update SideDrawer
class SideDrawer extends StatefulWidget {
const SideDrawer({super.key});
@override
State<SideDrawer> createState() => _SideDrawerState();
}
class _SideDrawerState extends State<SideDrawer> {
Future signOut() async {
await FirebaseAuth.instance.signOut();
Navigator.popUntil(context, ModalRoute.withName("/"));
}
@override
Widget build(BuildContext context) {
return Drawer(
child: ListView(children: [
UserAccountsDrawerHeader(
accountName: Text('Junn Eric'),
accountEmail: Text('junn.eric@utas.edu.om'),
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.white,
child: ClipOval(
child: Image(
image: AssetImage('images/profile.png'),
fit: BoxFit.cover,
width: 100.0,
height: 100.0,
),
),
),
),
ListTile(
leading: Icon(Icons.home),
title: Text(
'Home',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
onTap: () {},
),
ListTile(
leading: Icon(Icons.question_answer),
title: Text(
'About',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
onTap: () {},
),
ListTile(
leading: Icon(Icons.question_answer),
title: Text(
'Add Popular Places',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => AddPopularPlace(),
));
},
),
ListTile(
leading: Icon(Icons.question_answer),
title: Text(
'View Popular Places',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ViewPopularPage(),
));
},
),
ListTile(
leading: Icon(Icons.edit_document),
title: Text(
'Registration',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => RegistrationPage(),
));
},
),
ListTile(
leading: Icon(Icons.login),
title: Text(
'Sign In',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => LoginPage(),
));
},
),
ListTile(
leading: Icon(Icons.logout),
title: Text(
'Sign Out',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
onTap: () {
signOut();
},
),
]),
);
}
}
Create add_popular_place.dart
Insert Stateful Widget AddPopularPlace
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
class AddPopularPlace extends StatefulWidget {
const AddPopularPlace({super.key});
@override
State<AddPopularPlace> createState() => _AddPopularPlaceState();
}
class _AddPopularPlaceState extends State<AddPopularPlace> {
final TextEditingController _placename = TextEditingController();
final TextEditingController _price = TextEditingController();
Future addPopular() async {
await FirebaseFirestore.instance
.collection('places')
.add({
'placename': _placename.text.trim(),
'price': _price.text.trim(),
})
.then(
(value) => ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Added Successfully'))),
)
.catchError(
(error) => ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Failed to add popular place: $error'),
)));
}
@override
void dispose() {
_placename.dispose();
_price.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Add Popular Place'),
backgroundColor: Colors.green,
),
body: Container(
decoration: BoxDecoration(color: Colors.green),
padding: EdgeInsets.all(10),
child: Column(children: [
SizedBox(
height: 50,
),
Text('Popular Place Entry Form',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white)),
SizedBox(
height: 20,
),
TextFormField(
controller: _placename,
decoration: InputDecoration(
labelText: 'Place Name',
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(),
),
),
SizedBox(
height: 20,
),
TextFormField(
controller: _price,
decoration: InputDecoration(
labelText: 'Price',
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(),
),
),
SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () {
addPopular();
},
child: Text('Add'),
)
]),
),
);
}
}
Create view_popular_place.dart
insert ViewPopularPlace Stateful Widget
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class ViewPopularPage extends StatefulWidget {
const ViewPopularPage({super.key});
@override
State<ViewPopularPage> createState() => _ViewPopularPageState();
}
class _ViewPopularPageState extends State<ViewPopularPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('View Popular Place'),
centerTitle: true,
),
body: Container(
child: StreamBuilder(
stream: FirebaseFirestore.instance.collection('places').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
var docId = snapshot.data!.docs[index].id;
var placeName = snapshot.data!.docs[index]['placename'];
var placePrice = snapshot.data!.docs[index]['price'];
return Card(
child: ListTile(
title: Text(placeName),
subtitle: Text(placePrice),
trailing:
Row(mainAxisSize: MainAxisSize.min, children: [
GestureDetector(
child: Icon(Icons.edit), onTap: () {}),
GestureDetector(
child: Icon(Icons.delete), onTap: () {}),
]),
),
);
},
);
}
return Container();
}),
),
);
}
}
create edit_popular_place.dart
insert EditPopularPlace stateful Widget
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class EditPopularPlace extends StatefulWidget {
String popularname;
String price;
String docId;
EditPopularPlace(
{super.key,
required this.popularname,
required this.price,
required this.docId});
@override
State<EditPopularPlace> createState() => _EditPopularPlaceState();
}
class _EditPopularPlaceState extends State<EditPopularPlace> {
final TextEditingController _popularname = TextEditingController();
final TextEditingController _price = TextEditingController();
Future updatePopularPlace() async {
await FirebaseFirestore.instance
.collection('places')
.doc(widget.docId)
.update({
'placename': _popularname.text.trim(),
'price': _price.text.trim(),
})
.then((value) => ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Updated Successfully'))))
.catchError(
(error) => ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Failed to update popular place: $error'),
)));
}
@override
void dispose() {
_popularname.dispose();
_price.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Edit Popular Place'),
centerTitle: true,
),
body: Container(
padding: EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextFormField(
controller: _popularname..text = widget.popularname,
decoration: InputDecoration(
labelText: 'Place Name',
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(),
),
),
SizedBox(
height: 20,
),
TextFormField(
controller: _price..text = widget.price,
decoration: InputDecoration(
labelText: 'Price',
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(),
),
),
SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () {
updatePopularPlace();
},
child: Text('Update'),
),
],
)),
);
}
}
Note:
controller : _popularname..text = widget.popularname
This is equal to
_popularname.text = widget.popularname
controller: _popularname
update view_popular_place.dart
GestureDetector(
child: Icon(Icons.edit),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return EditPopularPlace(
popularname: placeName,
price: placePrice,
docId: docId);
}));
}),
update view_popular_place.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:tourismapp/edit_popular_place.dart';
class ViewPopularPage extends StatefulWidget {
const ViewPopularPage({super.key});
@override
State<ViewPopularPage> createState() => _ViewPopularPageState();
}
class _ViewPopularPageState extends State<ViewPopularPage> {
deletePlace(docId) async {
final result = await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Are you sure?'),
content: const Text(
'This action is permanent and can not be undone.',
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('Delete'),
)
],
),
);
if (result == true) {
await FirebaseFirestore.instance.collection('places').doc(docId).delete();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.green,
title: Text('View Popular Place'),
centerTitle: true,
),
body: Container(
padding: EdgeInsets.all(20),
child: StreamBuilder(
stream: FirebaseFirestore.instance.collection('places').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
var docId = snapshot.data!.docs[index].id;
var placeName = snapshot.data!.docs[index]['placename'];
var placePrice = snapshot.data!.docs[index]['price'];
return Card(
child: ListTile(
title: Text(placeName),
subtitle: Text(placePrice),
trailing:
Row(mainAxisSize: MainAxisSize.min, children: [
GestureDetector(
child: Icon(Icons.edit),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return EditPopularPlace(
popularname: placeName,
price: placePrice,
docId: docId);
}));
}),
GestureDetector(
child: Icon(Icons.delete),
onTap: () {
deletePlace(docId);
}),
]),
),
);
},
);
}
return Container();
}),
),
);
}
}