diff --git a/lib/AppWorkerData.dart b/lib/AppWorkerData.dart new file mode 100644 index 00000000..5e5e14c7 --- /dev/null +++ b/lib/AppWorkerData.dart @@ -0,0 +1,485 @@ +import 'package:budget_worker/FirebaseFunctions.dart'; +import 'package:budget_worker/showSnacBar.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:intl/intl.dart'; +import 'package:random_string/random_string.dart'; + +import 'Booking.dart'; +import 'auth.dart'; + +class AppWorkerData extends StatefulWidget { + final String text , cost , uid ; + AppWorkerData({Key? key, required this.text, required this.cost , required this.uid}); + + @override + State createState() => _AppWorkerData(text , cost , uid); +} + +class _AppWorkerData extends State { + String text , cost , uid; + _AppWorkerData(this.text , this.cost , this.uid); + final formKey = GlobalKey(); + String flat = "" , landmark = " " , state = ""; + TextEditingController dateInput = TextEditingController(); + TextEditingController timeinput = TextEditingController(); + @override + void initState() { + dateInput.text = ""; + timeinput.text = ""; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var doc = snapshot.data!.data(); + var fname = doc['FirstName']; + var lname = doc['LastName']; + var u_contact = doc['contact']; + var u_email = doc['email']; + var id = doc['uid']; + + return StreamBuilder( + stream: FirebaseFirestore.instance.collection(text).doc(uid).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var userDocument = snapshot.data!.data(); + String name = userDocument["name"]; + String contact = userDocument["contact"]; + String exp = userDocument['Experience']; + String brief = userDocument['Brief']; + String age = userDocument["Age"]; + String gender = userDocument["gender"]; + String imgUrl = userDocument["workerImage"]; + String work = userDocument['WorkerOpted']; + String w_email = userDocument['email']; + String worker_uuid = userDocument['WorkerUID']; + String work_type = userDocument['WorkType']; + String work_opted = userDocument['WorkerOpted']; + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Form( + child: Column(children: [ + Padding( + padding: const EdgeInsets.all(25), + child: CircleAvatar( + radius: 100, + backgroundImage: NetworkImage(imgUrl), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Name : ""$name", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Age : $age", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Gender : $gender", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Experience : $exp year(s)" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Work : $work" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.center, + padding: const EdgeInsets.all(10), + child: Text( + brief , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(10), + child: Text( + "Cost : $cost /-" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(10), + child: TextButton.icon( + onPressed: () { }, + label: Text( + contact , + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + icon: Icon(Icons.call_outlined , color: HexColor('#0B4360')), + ), + ), + + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + showModalBottomSheet( + context: context, + builder: (BuildContext context){ + return Container( + color: HexColor('#ffe6e6'), + padding: const EdgeInsets.all(10), + child: Form( + key: formKey, + child: ListView( + children: [ + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter your address *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: K/202 , Society name/Bungalow name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + flat = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter Landmark *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: Near Seasons mall", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + landmark = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter City and State *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: Pune, Maharashtra", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + state = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + controller: dateInput, + decoration: InputDecoration( + icon: Icon(Icons.calendar_today , color: HexColor('#0B4360')), + labelText: 'Choose Date', + ), + readOnly: true, + onTap: () async{ + DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1950), + //DateTime.now() - not to allow to choose before today. + lastDate: DateTime(2100)); + + if (pickedDate != null) { + print(pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000 + String formattedDate = DateFormat('yyyy-MM-dd').format(pickedDate); + print(formattedDate); //formatted date output using intl package => 2021-03-16 + setState(() { + dateInput.text = formattedDate; //set output date to TextField value. + }); + } else { + } + }, + validator: (value){ + if(value!.isEmpty){ + return "Please choose date"; + } + else{ + return null; + } + }, + onSaved: (value){ + dateInput.text = value!; + }, + ), + + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + controller: timeinput, //editing controller of this TextField + decoration: InputDecoration( + icon: Icon(Icons.timer_outlined , color: HexColor('#0B4360')), //icon of text field + labelText: "Enter Time" //label text of field + ), + readOnly: true, + onTap: () async { + TimeOfDay? pickedTime = await showTimePicker( + initialTime: TimeOfDay.now(), + context: context, + ); + if(pickedTime != null ){ + print(pickedTime.format(context)); //output 10:51 PM + DateTime parsedTime = DateFormat.jm().parse(pickedTime.format(context).toString()); + //converting to DateTime so that we can further format on different pattern. + print(parsedTime); //output 1970-01-01 22:53:00.000 + String formattedTime = DateFormat('HH:mm:ss').format(parsedTime); + print(formattedTime); //output 14:59:00 + //DateFormat() is from intl package, you can format the time on any pattern you need. + setState(() { + timeinput.text = formattedTime; //set the value of text field. + }); + }else{ + print("Time is not selected"); + } + }, + validator: (value){ + if(value!.isEmpty){ + return "Please choose time"; + } + else{ + return null; + } + }, + onSaved: (value){ + timeinput.text = value!; + }, + ), + ), + + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextButton.icon( + onPressed: () { }, + label: Text( + 'Pay '+cost+" when work is completed", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + icon: Icon(Icons.attach_money_outlined , color: HexColor('#0B4360')), + ), + ), + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + if(formKey.currentState!.validate()){ + formKey.currentState!.save(); + String w_approval = 'Not Approved' , payment_sts = 'Not Done' , work_sts = 'Not Started'; + String booking_no = randomAlphaNumeric(8); + + FirestoreServices2.booking(fname, lname,u_email, u_contact, flat, Auth.getUid(), landmark, state, dateInput.text.toString(), timeinput.text.toString(),imgUrl, work , name, uid, w_email ,contact, w_approval, cost, payment_sts, work_sts , text , worker_uuid , booking_no , work_type , work_opted); + Navigator.of(context).pop(); + Navigator.push(context, MaterialPageRoute(builder: (context) => const Booking())); + + } + else{ + showSnacBar(context, "Error"); + } + }, + child: Text( + "Confirm", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + ); + } + ); + + }, + child: Text( + "Book Now", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + + ], + ), + ), + );});}); + + } +} diff --git a/lib/AppWorkerList.dart b/lib/AppWorkerList.dart new file mode 100644 index 00000000..3b4a0cb7 --- /dev/null +++ b/lib/AppWorkerList.dart @@ -0,0 +1,121 @@ +import 'package:budget_worker/AppWorkerData.dart'; +import 'package:budget_worker/showSnacBar.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'CleanWorkerData.dart'; + +class AppWorkerList extends StatelessWidget { + final String text , cost; + const AppWorkerList({Key? key, required this.text, required this.cost}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(text), + ), + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(30), + child: Text( + 'Workers for $text', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 22, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ), + ), + ), + Expanded( + child: SizedBox( + height: 700, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection(text).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasError) { + return const Text('Something went wrong'); + } + if (snapshot.connectionState == ConnectionState.waiting) { + return const Text("Loading"); + } + + return ListView( + shrinkWrap: true, + children: snapshot.data!.docs.map((DocumentSnapshot document){ + Map data = document.data()! as Map; + return Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + ListTile( + title: Text( + data['name'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + onTap: (){ + Navigator.push(context , MaterialPageRoute(builder: (context) => AppWorkerData(text : text , cost : cost , uid : data['uid']))); + + }, + leading: CircleAvatar(backgroundColor: Colors.white60, backgroundImage: NetworkImage(data['workerImage']),radius: 30,), + subtitle: Text( + "${'Experience of '+data['Experience']} year(s)", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + ), + Container( + padding: const EdgeInsets.all(0), + alignment: Alignment.bottomRight, + child: TextButton.icon( + onPressed: () { }, + label: Text( + data['rating'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + icon: Icon(Icons.star , color: HexColor('#0B4360')), + ) + ), + + ],), + ); + }).toList(), + ); + }), + ), + ), + ].reversed.toList(), + ), + ), + ); + } +} diff --git a/lib/Booking.dart b/lib/Booking.dart new file mode 100644 index 00000000..2523fa40 --- /dev/null +++ b/lib/Booking.dart @@ -0,0 +1,305 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_rating_bar/flutter_rating_bar.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'auth.dart'; + +class Booking extends StatefulWidget { + const Booking({Key? key}) : super(key: key); + + @override + State createState() => _BookingState(); +} + +class _BookingState extends State { + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot){ + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var userDocument = snapshot.data!.data(); + String email = userDocument["email"]; + + return Scaffold( + appBar: AppBar( + title: Text( + "Bookings" , style: GoogleFonts.alata( + color: Colors.white, + fontStyle: FontStyle.normal, + ), + ), + ), + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(20), + alignment: Alignment.centerLeft, + child: Text( + 'Your Bookings ', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 21, + ), + ), + ), + Expanded( + child: SizedBox( + height: 700, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection("Booking").where("User_email" , isEqualTo: email).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot){ + if (snapshot.hasError) { + return const Text('Something went wrong'); + } + if (snapshot.connectionState == ConnectionState.waiting) { + return const Text("Loading"); + } + return ListView( + shrinkWrap: true, + children: snapshot.data!.docs.map((DocumentSnapshot document){ + Map db = document.data()! as Map; + String bid = db['bookingId']; + return Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + ListTile( + title: Text( + db['Work'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + + leading: CircleAvatar(backgroundColor: Colors.white60, backgroundImage: NetworkImage(db['Worker_image']), radius: 23,), + subtitle: Text( + db['booking_date'] +", "+ db['booking_time'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 14, + ), + ), + onTap: (){ + setState(() { + showModalBottomSheet( + context: context, + builder: (BuildContext context){ + return Container( + color: HexColor('#ffe6e6'), + padding: const EdgeInsets.all(10), + child: SizedBox( + height: 300, + child: Column( + children: [ + Container( + padding: const EdgeInsets.all(0), + alignment: Alignment.bottomRight, + child: TextButton.icon( + onPressed: () { + + }, + label: Text( + db['Work_sts'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + icon: Icon(Icons.incomplete_circle , color: HexColor('#0B4360')), + ), + ), + if(db['Work_sts'] == "Not Started") ...[ + Container( + padding: const EdgeInsets.all(10), + child: Text( + 'Work has not started yet , status will get updated when the work starts ', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + ), + ], + + Container( + padding: const EdgeInsets.all(10), + child: Text( + '${'Worker Name : '+db['Worker_name']}\nWorker Contact : '+db['Worker_contact'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + ), + + if(db['Work_sts'] == 'Started') ...[ + Text( + db['Worker_name'] + " has started "+db['Work']+ " work", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + Text('After the work gets completed click the complete button below', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + FirebaseFirestore.instance.collection('Booking').doc(bid).update({'Work_sts': 'Completed'}); + }, + child: Text( + 'Complete', + style: GoogleFonts.alata(color: Colors.white), + ) + ) + ], + if(db['Work_sts'] == 'Completed') ...[ + Container( + padding: EdgeInsets.all(10), + child: Text( + '${'${'Please pay '+db['Worker_name']} '+db['Cost']} /-', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ) + ], + if(db['Payment_sts'] == 'Done') ...[ + Container( + padding : const EdgeInsets.all(10), + child : Text( + 'Please rate our worker', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + + Container( + padding : const EdgeInsets.all(10), + child: RatingBar.builder( + initialRating: 3, + minRating: 1, + direction: Axis.horizontal, + allowHalfRating: true, + itemCount: 5, + itemPadding: const EdgeInsets.symmetric(horizontal: 4.0), + itemBuilder : (context , _) => + Icon( + Icons.star , color: HexColor('#0B4360'),), + onRatingUpdate: (rating){ + String comment = ""; + String name = db['UserFname'] + " "+ db['UserLname']; + String email = db['Worker_email']; + String work = db['Work_type']+', '+db['Work_opted']; + String rate = rating.toString(); + + print(rating); + if(rating == 1){ + comment = "Bad"; + FirebaseFirestore.instance.collection("Reviews").doc(db['Booking_No']).set({'worker_name' : name , 'worker_email' : email ,'rating' : rate , 'comment' : comment , 'work' : work}); + FirebaseFirestore.instance.collection('Booking').doc(bid).delete(); + } + if(rating == 2 ){ + comment = "Satisfactory"; + FirebaseFirestore.instance.collection("Reviews").doc(db['Booking_No']).set({'worker_name' : name , 'worker_email' : email ,'rating' : rate , 'comment' : comment , 'work' : work}); + FirebaseFirestore.instance.collection('Booking').doc(bid).delete(); + } + if(rating == 3){ + comment = "Can do better"; + FirebaseFirestore.instance.collection("Reviews").doc(db['Booking_No']).set({'worker_name' : name , 'worker_email' : email ,'rating' : rate , 'comment' : comment , 'work' : work}); + FirebaseFirestore.instance.collection('Booking').doc(bid).delete(); + } + if(rating == 4){ + comment = "Impressive"; + FirebaseFirestore.instance.collection("Reviews").doc(db['Booking_No']).set({'worker_name' : name , 'worker_email' : email ,'rating' : rate , 'comment' : comment , 'work' : work}); + FirebaseFirestore.instance.collection('Booking').doc(bid).delete(); + } + if(rating == 5){ + comment = "Excellent"; + FirebaseFirestore.instance.collection("Reviews").doc(db['Booking_No']).set({'worker_name' : name , 'worker_email' : email ,'rating' : rate , 'comment' : comment , 'work' : work}); + FirebaseFirestore.instance.collection('Booking').doc(bid).delete(); + } + Navigator.of(context).pop(); + }, + ), + ), + ], + if(db['Payment_sts'] == 'Incomplete') ...[ + Container( + padding: EdgeInsets.all(10), + child: Text( + '${'Payment has been incomplete please pay the worker '+ db['Cost']} /-', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + ], + ], + ), + ), + ); + } + ); + }); + }, + ), + ],), + ); + } , ).toList(), + ); + }, + ), + ) + ), + ].reversed.toList(), + ), + ), + ); + }); + } +} diff --git a/lib/CleanWorkerData.dart b/lib/CleanWorkerData.dart new file mode 100644 index 00000000..2323fd1b --- /dev/null +++ b/lib/CleanWorkerData.dart @@ -0,0 +1,491 @@ +import 'package:budget_worker/FirebaseFunctions.dart'; +import 'package:budget_worker/showSnacBar.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:intl/intl.dart'; +import 'package:random_string/random_string.dart'; + +import 'Booking.dart'; +import 'auth.dart'; + +class CleanWorkerData extends StatefulWidget { + final String text , cost , uid ; + + CleanWorkerData({Key? key, required this.text, required this.cost , required this.uid}); + + + @override + State createState() => _CleanWorkerDataState(text , cost , uid); +} + +class _CleanWorkerDataState extends State { + String text , cost , uid; + _CleanWorkerDataState(this.text , this.cost , this.uid); + final formKey = GlobalKey(); + String flat = "" , landmark = " " , state = ""; + TextEditingController dateInput = TextEditingController(); + TextEditingController timeinput = TextEditingController(); + @override + void initState() { + dateInput.text = ""; + timeinput.text = ""; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var doc = snapshot.data!.data(); + var fname = doc['FirstName']; + var lname = doc['LastName']; + var u_contact = doc['contact']; + var u_email = doc['email']; + var id = doc['uid']; + + return StreamBuilder( + stream: FirebaseFirestore.instance.collection(text).doc(uid).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var userDocument = snapshot.data!.data(); + String name = userDocument["name"]; + String contact = userDocument["contact"]; + String exp = userDocument['Experience']; + String brief = userDocument['Brief']; + String age = userDocument["Age"]; + String gender = userDocument["gender"]; + String imgUrl = userDocument["workerImage"]; + String work = userDocument['WorkerOpted']; + String w_email = userDocument['email']; + String worker_uuid = userDocument['WorkerUID']; + String work_type = userDocument['WorkType']; + String work_opted = userDocument['WorkerOpted']; + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Form( + child: Column(children: [ + Padding( + padding: const EdgeInsets.all(25), + child: CircleAvatar( + radius: 100, + backgroundImage: NetworkImage(imgUrl), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Name : ""$name", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Age : $age", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Gender : $gender", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Experience : $exp year(s)" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Work : $work" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.center, + padding: const EdgeInsets.all(10), + child: Text( + brief , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(10), + child: Text( + "Cost : $cost /-" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(10), + child: TextButton.icon( + onPressed: () { }, + label: Text( + contact , + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + icon: Icon(Icons.call_outlined , color: HexColor('#0B4360')), + ), + ), + + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + showModalBottomSheet( + context: context, + builder: (BuildContext context){ + return Container( + color: HexColor('#ffe6e6'), + padding: const EdgeInsets.all(10), + child: Form( + key: formKey, + child: ListView( + children: [ + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter your address *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: K/202 , Society name/Bungalow name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + flat = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter Landmark *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: Near Seasons mall", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + landmark = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter City and State *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: Pune, Maharashtra", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + state = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + controller: dateInput, + decoration: InputDecoration( + icon: Icon(Icons.calendar_today , color: HexColor('#0B4360')), + labelText: 'Choose Date', + ), + readOnly: true, + onTap: () async{ + DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1950), + //DateTime.now() - not to allow to choose before today. + lastDate: DateTime(2100)); + + if (pickedDate != null) { + print(pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000 + String formattedDate = DateFormat('yyyy-MM-dd').format(pickedDate); + print(formattedDate); //formatted date output using intl package => 2021-03-16 + setState(() { + dateInput.text = formattedDate; //set output date to TextField value. + }); + } else { + } + }, + validator: (value){ + if(value!.isEmpty){ + return "Please choose date"; + } + else{ + return null; + } + }, + onSaved: (value){ + dateInput.text = value!; + }, + ), + + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + controller: timeinput, //editing controller of this TextField + decoration: InputDecoration( + icon: Icon(Icons.timer_outlined , color: HexColor('#0B4360')), //icon of text field + labelText: "Enter Time" //label text of field + ), + readOnly: true, + onTap: () async { + TimeOfDay? pickedTime = await showTimePicker( + initialTime: TimeOfDay.now(), + context: context, + ); + if(pickedTime != null ){ + print(pickedTime.format(context)); //output 10:51 PM + DateTime parsedTime = DateFormat.jm().parse(pickedTime.format(context).toString()); + //converting to DateTime so that we can further format on different pattern. + print(parsedTime); //output 1970-01-01 22:53:00.000 + String formattedTime = DateFormat('HH:mm:ss').format(parsedTime); + print(formattedTime); //output 14:59:00 + //DateFormat() is from intl package, you can format the time on any pattern you need. + setState(() { + timeinput.text = formattedTime; //set the value of text field. + }); + }else{ + print("Time is not selected"); + } + }, + validator: (value){ + if(value!.isEmpty){ + return "Please choose time"; + } + else{ + return null; + } + }, + onSaved: (value){ + timeinput.text = value!; + }, + ), + ), + + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextButton.icon( + onPressed: () { }, + label: Text( + 'Pay '+cost+" when work is completed", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + icon: Icon(Icons.attach_money_outlined , color: HexColor('#0B4360')), + ), + ), + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + if(formKey.currentState!.validate()){ + formKey.currentState!.save(); + String w_approval = 'Not Approved' , payment_sts = 'Not Done' , work_sts = 'Not Started'; + String booking_no = randomAlphaNumeric(8); + + FirestoreServices2.booking(fname, lname,u_email, u_contact, flat, Auth.getUid(), landmark, state, dateInput.text.toString(), timeinput.text.toString(),imgUrl, work , name, uid, w_email ,contact, w_approval, cost, payment_sts, work_sts , text , worker_uuid , booking_no , work_type , work_opted); + Navigator.of(context).pop(); + Navigator.push(context, MaterialPageRoute(builder: (context) => const Booking())); + + } + else{ + showSnacBar(context, "Error"); + } + }, + child: Text( + "Confirm", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + ); + } + ); + + }, + child: Text( + "Book Now", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + + ], + + + ), + + ), + + );});}); + + } +} diff --git a/lib/CleanWorkerList.dart b/lib/CleanWorkerList.dart new file mode 100644 index 00000000..41cba24c --- /dev/null +++ b/lib/CleanWorkerList.dart @@ -0,0 +1,120 @@ +import 'package:budget_worker/showSnacBar.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'CleanWorkerData.dart'; + +class CleanWorkerList extends StatelessWidget { + final String text , cost; + const CleanWorkerList({Key? key, required this.text, required this.cost}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(text), + ), + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(30), + child: Text( + 'Workers for $text', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 22, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ), + ), + ), + Expanded( + child: SizedBox( + height: 700, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection(text).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasError) { + return const Text('Something went wrong'); + } + if (snapshot.connectionState == ConnectionState.waiting) { + return const Text("Loading"); + } + + return ListView( + shrinkWrap: true, + children: snapshot.data!.docs.map((DocumentSnapshot document){ + Map data = document.data()! as Map; + return Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + ListTile( + title: Text( + data['name'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + onTap: (){ + Navigator.push(context , MaterialPageRoute(builder: (context) => CleanWorkerData(text : text , cost : cost , uid : data['uid']))); + + }, + leading: CircleAvatar(backgroundColor: Colors.white60, backgroundImage: NetworkImage(data['workerImage']),radius: 30,), + subtitle: Text( + "${'Experience of '+data['Experience']} year(s)", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + ), + Container( + padding: const EdgeInsets.all(0), + alignment: Alignment.bottomRight, + child: TextButton.icon( + onPressed: () { }, + label: Text( + data['rating'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + icon: Icon(Icons.star , color: HexColor('#0B4360')), + ) + ), + + ],), + ); + }).toList(), + ); + }), + ), + ), + ].reversed.toList(), + ), + ), + ); + } +} diff --git a/lib/Dashboard.dart b/lib/Dashboard.dart new file mode 100644 index 00000000..7230e015 --- /dev/null +++ b/lib/Dashboard.dart @@ -0,0 +1,63 @@ +import 'package:budget_worker/HomePage.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'Booking.dart'; +import 'UserAcc.dart'; + +class Dashboard extends StatefulWidget { + const Dashboard({Key? key}) : super(key: key); + + @override + State createState() => _DashboardState(); +} + +class _DashboardState extends State { + int index = 0; + final _screens = [ + const HomePage(), + const Booking(), + const UserAcc(), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: _screens[index], + backgroundColor : HexColor('#ffe6e6'), + + bottomNavigationBar: NavigationBarTheme( + data: NavigationBarThemeData( + indicatorColor: HexColor('#76c7ef'), + labelTextStyle: MaterialStateProperty.all( + const TextStyle(fontSize: 14 , fontWeight: FontWeight.w500 , color: Colors.white), + ), + ), + child: NavigationBar( + height: 60, + backgroundColor: HexColor('#0B4360'), + selectedIndex: index, + onDestinationSelected: (index) => setState(() { + this.index = index; + }), + destinations: const [ + NavigationDestination( + icon: Icon(Icons.home_outlined, color: Colors.white,), + label: "Home", + ), + NavigationDestination( + icon: Icon(Icons.bookmark_border_rounded, color: Colors.white,), + label: "Bookings" , + ), + NavigationDestination( + icon: Icon(Icons.person_outline, color: Colors.white,), + label: "Account" , + ), + ], + ), + ), + ); + } +} + diff --git a/lib/FirebaseFunctions.dart b/lib/FirebaseFunctions.dart new file mode 100644 index 00000000..5d89f88a --- /dev/null +++ b/lib/FirebaseFunctions.dart @@ -0,0 +1,49 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:random_string/random_string.dart'; + +class FirestoreServices{ + static saveUser(String name,lastname , email , contact , uid) async{ + await FirebaseFirestore.instance + .collection('UserData') + .doc(uid) + .set({'email' : email , 'FirstName' : name , 'LastName' : lastname , 'contact' : contact , 'uid' : uid}); + } +} +class FirestoreServices2{ + static booking(String u_fname , u_lname ,u_email , u_contact , u_flat ,u_uid, u_landmark , u_state ,date , time, w_image , work , w_name ,w_uid,w_email, w_contact , w_approval , cost , payment_sts , work_sts , text , worker_uuid , booking_no , work_type , work_opted) async{ + String id = randomAlphaNumeric(5); + + await FirebaseFirestore.instance + .collection('Booking') + .doc(id) + .set({ + 'UserFname' : u_fname, + 'UserLname' : u_lname, + 'User_Contact' : u_contact, + 'User_flat' : u_flat, + 'User_Landmark' : u_landmark, + 'User_state' : u_state, + 'User_uid' : u_uid, + 'User_email' : u_email, + 'booking_date':date, + 'booking_time':time, + 'Worker_image':w_image, + 'Work' : work, + 'Worker_name':w_name, + 'Worker_email' : w_email, + 'Worker_contact':w_contact, + 'Worker_uid' : w_uid, + 'Worker_approval_sts':w_approval, + 'Cost' : cost, + 'Payment_sts':payment_sts, + 'Work_sts' : work_sts, + 'bookingId' : id, + 'DBName' : text, + 'WorkerUID' : worker_uuid, + 'Booking_No' : booking_no, + 'Work_type' : work_type, + 'Work_opted' : work_opted + }); + } + +} \ No newline at end of file diff --git a/lib/ForgotPassword.dart b/lib/ForgotPassword.dart new file mode 100644 index 00000000..6acb5d51 --- /dev/null +++ b/lib/ForgotPassword.dart @@ -0,0 +1,102 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:lottie/lottie.dart'; + +import 'auth.dart'; + +class ForgotPassword extends StatefulWidget { + const ForgotPassword({Key? key}) : super(key: key); + + @override + State createState() => _ForgotPasswordState(); +} + +class _ForgotPasswordState extends State { + TextEditingController email = TextEditingController(); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(20), + child: Text( + 'Forgot Password ?', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 30, + color: HexColor('#0B4360'), + fontWeight: FontWeight.bold, + fontStyle: FontStyle.normal, + ), + ), + ), + Container( + padding: const EdgeInsets.all(20), + height: 120, + width: 160, + child: Text( + 'We understand that forgetting your password can be frustrating. Let us help you reset it so you can continue using our service hassle-free', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 15, + color: HexColor('#0B4360'), + fontWeight: FontWeight.bold, + fontStyle: FontStyle.normal, + ), + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: Lottie.asset( + 'assets/JSON/bwFP.json', + height: 270.0, + repeat: true, + reverse: true, + animate: true, + ), + ), + + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + keyboardType: TextInputType.emailAddress, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.alternate_email_rounded , color: HexColor('#0B4360'),), + labelText: "Enter Registered Email", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + controller: email, + ), + ), + Container( + height: 90.0, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + Auth.resetPassword(email.text.toString() , context); + }, + child: Text( + "Send Verification Link", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ].reversed.toList(), + ), + ), + ); + } +} diff --git a/lib/HomePage.dart b/lib/HomePage.dart new file mode 100644 index 00000000..e126fb53 --- /dev/null +++ b/lib/HomePage.dart @@ -0,0 +1,354 @@ +import 'package:budget_worker/AppWorkerList.dart'; +import 'package:budget_worker/QuickWorkerList.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'Booking.dart'; +import 'CleanWorkerList.dart'; +import 'auth.dart'; + +class HomePage extends StatefulWidget { + const HomePage({Key? key}) : super(key: key); + + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State { + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var userDocument = snapshot.data!.data(); + String fname = userDocument["FirstName"]; + + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 15, + margin: const EdgeInsets.all(20), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(20), + child: Text( + 'Hi, $fname', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 25, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ), + ), + ),], + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: CupertinoSearchTextField( + backgroundColor: Colors.white, + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.displayLarge, + fontSize: 18, + color: HexColor('#0B4360'), + fontWeight: FontWeight.normal, + fontStyle: FontStyle.normal, + ), + placeholder: 'Search for Cleaning , Massage , Cooking etc..', + placeholderStyle: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.displayLarge, + fontSize: 18, + color: Colors.blueGrey, + fontWeight: FontWeight.normal, + fontStyle: FontStyle.normal, + ), + autocorrect: true, + ), + ), + + Container( + padding: const EdgeInsets.all(25), + child: Text( + "Cleaning & Dusting", + style: GoogleFonts.alata( + fontSize: 20, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + Expanded( + child: SizedBox( + height: 290, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection("Cleaning").snapshots(), + builder: (context , snapshot){ + return ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: snapshot.data?.docs.length, + itemBuilder: (context , index){ + DocumentSnapshot db = snapshot.data?.docs[index] as DocumentSnapshot; + return Container( + width: 235, + padding: const EdgeInsets.all(10), + child: Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + Container( + padding: const EdgeInsets.all(10), + child: Image.network(db['image']), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + db['title'], + style: GoogleFonts.alata( + fontSize: 15, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + db['desc'], + style: GoogleFonts.alata( + fontSize: 14, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w500, + ), + ), + ), + Container( + padding: const EdgeInsets.all(5), + child: TextButton( + onPressed: () { + Navigator.push(context , MaterialPageRoute(builder: (context) => CleanWorkerList(text : db['dbName'] , cost : db['cost']))); + }, + child: Text( + "View", + style: GoogleFonts.alata( + fontSize: 14, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ],), + ), + ); + }, + ); + } + ), + ), + ), + Container( + padding: const EdgeInsets.all(25), + child: Text( + "Appliance Repair", + style: GoogleFonts.alata( + fontSize: 20, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + Expanded( + child: SizedBox( + height: 290, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection("ApplianceRepair").snapshots(), + builder: (context , snapshot){ + return ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: snapshot.data?.docs.length, + itemBuilder: (context , index){ + DocumentSnapshot db = snapshot.data?.docs[index] as DocumentSnapshot; + return Container( + width: 235, + padding: const EdgeInsets.all(10), + child: Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + Container( + padding: const EdgeInsets.all(10), + child: Image.network(db['image']), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + db['title'], + style: GoogleFonts.alata( + fontSize: 15, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + db['desc'], + style: GoogleFonts.alata( + fontSize: 14, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w500, + ), + ), + ), + Container( + padding: const EdgeInsets.all(5), + child: TextButton( + onPressed: () { + Navigator.push(context , MaterialPageRoute(builder: (context) => AppWorkerList(text : db['dbName'] , cost : db['cost']))); + }, + child: Text( + "View", + style: GoogleFonts.alata( + fontSize: 14, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ],), + ), + ); + }, + ); + } + ), + ), + ), + Container( + padding: const EdgeInsets.all(25), + child: Text( + "Quick Home Repair", + style: GoogleFonts.alata( + fontSize: 20, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + Expanded( + child: SizedBox( + height: 290, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection("QuickHomeRepair").snapshots(), + builder: (context , snapshot){ + return ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: snapshot.data?.docs.length, + itemBuilder: (context , index){ + DocumentSnapshot db = snapshot.data?.docs[index] as DocumentSnapshot; + return Container( + width: 235, + padding: const EdgeInsets.all(10), + child: Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + Container( + padding: const EdgeInsets.all(10), + child: Image.network(db['image']), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + db['title'], + style: GoogleFonts.alata( + fontSize: 15, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + db['desc'], + style: GoogleFonts.alata( + fontSize: 14, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w500, + ), + ), + ), + Container( + padding: const EdgeInsets.all(5), + child: TextButton( + onPressed: () { + Navigator.push(context , MaterialPageRoute(builder: (context) => QuickWorkerList(text : db['dbName'] , cost : db['cost']))); + }, + child: Text( + "View", + style: GoogleFonts.alata( + fontSize: 14, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ],), + ), + ); + }, + ); + } + ), + ), + ), + ].reversed.toList(), + ), + ), + );}); + } +} \ No newline at end of file diff --git a/lib/LoginScreen.dart b/lib/LoginScreen.dart new file mode 100644 index 00000000..025f97eb --- /dev/null +++ b/lib/LoginScreen.dart @@ -0,0 +1,186 @@ +import 'package:budget_worker/HomePage.dart'; +import 'package:budget_worker/ForgotPassword.dart'; +import 'package:budget_worker/SignUp.dart'; +import 'package:budget_worker/showSnacBar.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:lottie/lottie.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'auth.dart'; + +class LoginScreen extends StatefulWidget { + const LoginScreen ({Key? key}) : super(key: key); + + @override + State createState() => _LoginScreenState(); +} + + +class _LoginScreenState extends State { + final formKey = GlobalKey(); + String email = "" , password = ""; + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(35), + height: 155, + width: 160, + child: Text( + 'Welcome, you have been missed !', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 30, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ), + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: Lottie.asset( + 'assets/JSON/bwLogin2.json', + height: 270.0, + repeat: true, + reverse: true, + animate: true, + ), + ), + Form( + key: formKey, + child: Column(children: [ + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + keyboardType: TextInputType.emailAddress, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.alternate_email_rounded , color: HexColor('#0B4360'),), + labelText: "Enter Email", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty || !RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)){ + return "Enter Correct Email Address"; + }else{ + return null; + } + }, + onSaved: (value){ + setState(() { + email = value!; + }); + }, + // controller: controller, + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + obscureText: true, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.key_outlined , color: HexColor('#0B4360'),), + labelText: "Enter Password", + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(30), + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + ) + ), + onSaved: (value){ + setState(() { + password = value!; + }); + }, + // controller: controller2, + ), + ), + Container( + padding: const EdgeInsets.all(5), + alignment: Alignment.centerRight, + child: TextButton.icon( + onPressed: () { + setState((){ + Navigator.push(context, MaterialPageRoute(builder: (context) => const ForgotPassword())); + }); + }, + label: Text( + 'Forgot Password ? ', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + textAlign: TextAlign.end, + ), + icon: Icon(Icons.email_outlined , color: HexColor('#0B4360'),), + ), + ), + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + if(formKey.currentState!.validate()){ + //check if form data are valid, + // your process task ahed if all data are valid + formKey.currentState!.save(); + Auth.signinUser(email, password, context); + } + else{ + showSnacBar(context, "Error"); + } + // loginUser(); + }, + child: Text( + "Verify", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + Container( + padding: const EdgeInsets.all(1), + child: const Divider( + color: Colors.grey, + height: 1, + thickness: 1, + ), + ), + Container( + padding: const EdgeInsets.all(1), + child: TextButton( + onPressed: () { + setState((){ + Navigator.push(context, MaterialPageRoute(builder: (context) => const SignUp())); + }); + }, + child: Text( + "Don't have an account yet ? Click here", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + ), + ), + ), + ), + ],), + ), + ].reversed.toList(), + ), + ), + ); + } +} diff --git a/lib/QuickWorkerData.dart b/lib/QuickWorkerData.dart new file mode 100644 index 00000000..4bffdc7b --- /dev/null +++ b/lib/QuickWorkerData.dart @@ -0,0 +1,485 @@ +import 'package:budget_worker/FirebaseFunctions.dart'; +import 'package:budget_worker/showSnacBar.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:intl/intl.dart'; +import 'package:random_string/random_string.dart'; + +import 'Booking.dart'; +import 'auth.dart'; + +class QuickWorkerData extends StatefulWidget { + final String text , cost , uid ; + QuickWorkerData({Key? key, required this.text, required this.cost , required this.uid}); + + @override + State createState() => _QuickWorkerData(text , cost , uid); +} + +class _QuickWorkerData extends State { + String text , cost , uid; + _QuickWorkerData(this.text , this.cost , this.uid); + final formKey = GlobalKey(); + String flat = "" , landmark = " " , state = ""; + TextEditingController dateInput = TextEditingController(); + TextEditingController timeinput = TextEditingController(); + @override + void initState() { + dateInput.text = ""; + timeinput.text = ""; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var doc = snapshot.data!.data(); + var fname = doc['FirstName']; + var lname = doc['LastName']; + var u_contact = doc['contact']; + var u_email = doc['email']; + var id = doc['uid']; + + return StreamBuilder( + stream: FirebaseFirestore.instance.collection(text).doc(uid).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var userDocument = snapshot.data!.data(); + String name = userDocument["name"]; + String contact = userDocument["contact"]; + String exp = userDocument['Experience']; + String brief = userDocument['Brief']; + String age = userDocument["Age"]; + String gender = userDocument["gender"]; + String imgUrl = userDocument["workerImage"]; + String work = userDocument['WorkerOpted']; + String w_email = userDocument['email']; + String worker_uuid = userDocument['WorkerUID']; + String work_type = userDocument['WorkType']; + String work_opted = userDocument['WorkerOpted']; + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Form( + child: Column(children: [ + Padding( + padding: const EdgeInsets.all(25), + child: CircleAvatar( + radius: 100, + backgroundImage: NetworkImage(imgUrl), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Name : ""$name", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Age : $age", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Gender : $gender", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Experience : $exp year(s)" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Work : $work" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.center, + padding: const EdgeInsets.all(10), + child: Text( + brief , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(10), + child: Text( + "Cost : $cost /-" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(10), + child: TextButton.icon( + onPressed: () { }, + label: Text( + contact , + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + icon: Icon(Icons.call_outlined , color: HexColor('#0B4360')), + ), + ), + + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + showModalBottomSheet( + context: context, + builder: (BuildContext context){ + return Container( + color: HexColor('#ffe6e6'), + padding: const EdgeInsets.all(10), + child: Form( + key: formKey, + child: ListView( + children: [ + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter your address *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: K/202 , Society name/Bungalow name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + flat = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter Landmark *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: Near Seasons mall", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + landmark = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter City and State *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: Pune, Maharashtra", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + state = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + controller: dateInput, + decoration: InputDecoration( + icon: Icon(Icons.calendar_today , color: HexColor('#0B4360')), + labelText: 'Choose Date', + ), + readOnly: true, + onTap: () async{ + DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1950), + //DateTime.now() - not to allow to choose before today. + lastDate: DateTime(2100)); + + if (pickedDate != null) { + print(pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000 + String formattedDate = DateFormat('yyyy-MM-dd').format(pickedDate); + print(formattedDate); //formatted date output using intl package => 2021-03-16 + setState(() { + dateInput.text = formattedDate; //set output date to TextField value. + }); + } else { + } + }, + validator: (value){ + if(value!.isEmpty){ + return "Please choose date"; + } + else{ + return null; + } + }, + onSaved: (value){ + dateInput.text = value!; + }, + ), + + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + controller: timeinput, //editing controller of this TextField + decoration: InputDecoration( + icon: Icon(Icons.timer_outlined , color: HexColor('#0B4360')), //icon of text field + labelText: "Enter Time" //label text of field + ), + readOnly: true, + onTap: () async { + TimeOfDay? pickedTime = await showTimePicker( + initialTime: TimeOfDay.now(), + context: context, + ); + if(pickedTime != null ){ + print(pickedTime.format(context)); //output 10:51 PM + DateTime parsedTime = DateFormat.jm().parse(pickedTime.format(context).toString()); + //converting to DateTime so that we can further format on different pattern. + print(parsedTime); //output 1970-01-01 22:53:00.000 + String formattedTime = DateFormat('HH:mm:ss').format(parsedTime); + print(formattedTime); //output 14:59:00 + //DateFormat() is from intl package, you can format the time on any pattern you need. + setState(() { + timeinput.text = formattedTime; //set the value of text field. + }); + }else{ + print("Time is not selected"); + } + }, + validator: (value){ + if(value!.isEmpty){ + return "Please choose time"; + } + else{ + return null; + } + }, + onSaved: (value){ + timeinput.text = value!; + }, + ), + ), + + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextButton.icon( + onPressed: () { }, + label: Text( + 'Pay '+cost+" when work is completed", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + icon: Icon(Icons.attach_money_outlined , color: HexColor('#0B4360')), + ), + ), + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + if(formKey.currentState!.validate()){ + formKey.currentState!.save(); + String w_approval = 'Not Approved' , payment_sts = 'Not Done' , work_sts = 'Not Started'; + String booking_no = randomAlphaNumeric(8); + + FirestoreServices2.booking(fname, lname,u_email, u_contact, flat, Auth.getUid(), landmark, state, dateInput.text.toString(), timeinput.text.toString(),imgUrl, work , name, uid, w_email ,contact, w_approval, cost, payment_sts, work_sts , text , worker_uuid , booking_no , work_type , work_opted); + Navigator.of(context).pop(); + Navigator.push(context, MaterialPageRoute(builder: (context) => const Booking())); + + } + else{ + showSnacBar(context, "Error"); + } + }, + child: Text( + "Confirm", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + ); + } + ); + + }, + child: Text( + "Book Now", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + + ], + ), + ), + );});}); + + } +} diff --git a/lib/QuickWorkerList.dart b/lib/QuickWorkerList.dart new file mode 100644 index 00000000..4faf4530 --- /dev/null +++ b/lib/QuickWorkerList.dart @@ -0,0 +1,120 @@ +import 'package:budget_worker/QuickWorkerData.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'CleanWorkerData.dart'; + +class QuickWorkerList extends StatelessWidget { + final String text , cost; + const QuickWorkerList({Key? key, required this.text, required this.cost}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(text), + ), + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(30), + child: Text( + 'Workers for $text', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 22, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ), + ), + ), + Expanded( + child: SizedBox( + height: 700, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection(text).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasError) { + return const Text('Something went wrong'); + } + if (snapshot.connectionState == ConnectionState.waiting) { + return const Text("Loading"); + } + + return ListView( + shrinkWrap: true, + children: snapshot.data!.docs.map((DocumentSnapshot document){ + Map data = document.data()! as Map; + return Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + ListTile( + title: Text( + data['name'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + onTap: (){ + Navigator.push(context , MaterialPageRoute(builder: (context) => QuickWorkerData(text : text , cost : cost , uid : data['uid']))); + + }, + leading: CircleAvatar(backgroundColor: Colors.white60, backgroundImage: NetworkImage(data['workerImage']),radius: 30,), + subtitle: Text( + "${'Experience of '+data['Experience']} year(s)", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + ), + Container( + padding: const EdgeInsets.all(0), + alignment: Alignment.bottomRight, + child: TextButton.icon( + onPressed: () { }, + label: Text( + data['rating'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + icon: Icon(Icons.star , color: HexColor('#0B4360')), + ) + ), + + ],), + ); + }).toList(), + ); + }), + ), + ), + ].reversed.toList(), + ), + ), + ); + } +} diff --git a/lib/SignUp.dart b/lib/SignUp.dart new file mode 100644 index 00000000..da047075 --- /dev/null +++ b/lib/SignUp.dart @@ -0,0 +1,258 @@ +import 'package:budget_worker/showSnacBar.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:lottie/lottie.dart'; + +import 'LoginScreen.dart'; +import 'auth.dart'; + +class SignUp extends StatefulWidget { + const SignUp({Key? key}) : super(key: key); + + @override + State createState() => _SignUpState(); +} + +class _SignUpState extends State { + final formKey = GlobalKey(); + String email = "" , password = "" , firstname = "" , contact = "" , lastname = "" , imgUrl = "" , age = ""; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(30), + child: Text( + 'Sign Up', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 40, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Lottie.asset( + 'assets/JSON/bwSignUp2.json', + height: 270.0, + repeat: true, + reverse: true, + animate: true, + ), + ), + Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15.0), + ), + elevation: 15, + margin: const EdgeInsets.all(30), + shadowColor: HexColor('#0B4360'), + child: Form( + key: formKey, + child : Column(children: [ + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + // focusNode: myFocusNode, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.person_add_alt_1_outlined, color: HexColor('#0B4360'),), + labelText: "Enter First Name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty || !RegExp(r'^[a-z A-Z]+$').hasMatch(value!)){ + //allow upper and lower case alphabets and space + return "Enter Correct Name"; + }else{ + return null; + } + }, + onSaved: (value){ + setState(() { + firstname = value!; + }); + }, + // controller: controller, + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + // focusNode: myFocusNode, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.person_add_alt_1_outlined, color: HexColor('#0B4360'),), + labelText: "Enter Last Name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty || !RegExp(r'^[a-z A-Z]+$').hasMatch(value!)){ + //allow upper and lower case alphabets and space + return "Enter Correct Name"; + }else{ + return null; + } + }, + onSaved: (value){ + setState(() { + lastname = value!; + }); + }, + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + keyboardType: TextInputType.emailAddress, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.alternate_email_rounded , color: HexColor('#0B4360'),), + labelText: "Enter Email Id", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty || !RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)){ + return "Enter Correct Email Address"; + }else{ + return null; + } + }, + onSaved: (value){ + setState(() { + email = value!; + }); + }, + // controller: controller2, + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + keyboardType: TextInputType.phone, + // focusNode: myFocusNode, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.phone, color: HexColor('#0B4360'),), + labelText: "Enter Contact Number", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty || !RegExp(r'^(?:[+0][1-9])?[0-9]{10}$').hasMatch(value)){ + return "Enter Correct Phone Number"; + }else{ + return null; + } + }, + onSaved: (value){ + setState(() { + contact = value!; + }); + }, + // controller: controller, + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + obscureText: true, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.password , color: HexColor('#0B4360'),), + labelText: "Set a Password", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + onSaved: (value){ + setState(() { + password = value!; + }); + }, + // controller: controller3, + ), + ), + Container( + height: 90.0, + width: 200.0, + padding: const EdgeInsets.all(25), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + if(formKey.currentState!.validate()){ + //check if form data are valid, + // your process task ahed if all data are valid + formKey.currentState!.save(); + Auth.signupUser(email, password, firstname, lastname, contact, context); + Navigator.push(context, MaterialPageRoute(builder: (context) => const LoginScreen())); + } + else{ + showSnacBar(context, "Error"); + } + }, + child: Text( + "Sign Up", + style: GoogleFonts.alata(), + ), + ), + ), + ],) + ), + ), + Container( + padding: const EdgeInsets.all(1), + child: const Divider( + color: Colors.grey, + height: 1, + thickness: 1, + ), + ), + Container( + padding: const EdgeInsets.all(1), + child: TextButton( + onPressed: () { + setState((){ + Navigator.push(context, MaterialPageRoute(builder: (context) => const LoginScreen())); + }); + }, + child: Text( + "Already have an account ? Login", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + ), + ), + ), + ), + ].reversed.toList(), + ), + ), + ); + } +} diff --git a/lib/UserAcc.dart b/lib/UserAcc.dart new file mode 100644 index 00000000..0723090f --- /dev/null +++ b/lib/UserAcc.dart @@ -0,0 +1,192 @@ +import 'package:budget_worker/showSnacBar.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'auth.dart'; + +class UserAcc extends StatefulWidget { + const UserAcc({Key? key}) : super(key: key); + + @override + State createState() => _UserAccState(); +} + +class _UserAccState extends State { + final formKey = GlobalKey(); + TextEditingController first_name = TextEditingController(); + TextEditingController last_name = TextEditingController(); + TextEditingController w_contact = TextEditingController(); + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var userDocument = snapshot.data!.data(); + String fname = userDocument["FirstName"]; + String lname = userDocument["LastName"]; + String contact = userDocument["contact"]; + String email = userDocument["email"]; + first_name.text = fname; + last_name.text = lname; + w_contact.text = contact; + + + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Form( + key: formKey, + child: Column(children: [ + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.topLeft, + child: Text( + "Your Account", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 22, + ), + ), + ), + Padding( + padding: const EdgeInsets.all(25), + child: CircleAvatar( + radius: 50, + backgroundColor: HexColor('#0B4360'), + child: Text( + fname.substring(0 , 1).toUpperCase(), + style: GoogleFonts.alata(color: Colors.white , fontSize: 28 , fontWeight: FontWeight.w600), + ), + ), + ), + Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + Container( + padding: const EdgeInsets.all(10), + child: TextField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.person_add_alt_1_outlined , color: HexColor('#0B4360'),), + labelText: "First Name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + controller: first_name, + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: TextField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.person_add_alt_1_outlined , color: HexColor('#0B4360'),), + labelText: "Last Name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + controller: last_name, + ), + ), + + Container( + padding: const EdgeInsets.all(10), + child: TextField( + keyboardType: TextInputType.number, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.person_add_alt_1_outlined , color: HexColor('#0B4360'),), + labelText: "Conatact", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + controller: w_contact, + ), + ), + + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Email : $email", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('#0B4360')), + onPressed: (){ + FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).update({ + 'FirstName' : first_name.text.toString(), + 'LastName' : last_name.text.toString(), + 'contact' : w_contact.text.toString(), + }); + showSnacBar(context, "Updated Successfully !"); + }, + child: Text( + "Update", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('#0B4360')), + onPressed: (){ + FirebaseAuth.instance.signOut(); + }, + child: Text( + "Sign out", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + ],), + ), + ].reversed.toList(), + ), + ), + );}); + } +} diff --git a/lib/app/AppWorkerData.dart b/lib/app/AppWorkerData.dart new file mode 100644 index 00000000..5e5e14c7 --- /dev/null +++ b/lib/app/AppWorkerData.dart @@ -0,0 +1,485 @@ +import 'package:budget_worker/FirebaseFunctions.dart'; +import 'package:budget_worker/showSnacBar.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:intl/intl.dart'; +import 'package:random_string/random_string.dart'; + +import 'Booking.dart'; +import 'auth.dart'; + +class AppWorkerData extends StatefulWidget { + final String text , cost , uid ; + AppWorkerData({Key? key, required this.text, required this.cost , required this.uid}); + + @override + State createState() => _AppWorkerData(text , cost , uid); +} + +class _AppWorkerData extends State { + String text , cost , uid; + _AppWorkerData(this.text , this.cost , this.uid); + final formKey = GlobalKey(); + String flat = "" , landmark = " " , state = ""; + TextEditingController dateInput = TextEditingController(); + TextEditingController timeinput = TextEditingController(); + @override + void initState() { + dateInput.text = ""; + timeinput.text = ""; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var doc = snapshot.data!.data(); + var fname = doc['FirstName']; + var lname = doc['LastName']; + var u_contact = doc['contact']; + var u_email = doc['email']; + var id = doc['uid']; + + return StreamBuilder( + stream: FirebaseFirestore.instance.collection(text).doc(uid).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var userDocument = snapshot.data!.data(); + String name = userDocument["name"]; + String contact = userDocument["contact"]; + String exp = userDocument['Experience']; + String brief = userDocument['Brief']; + String age = userDocument["Age"]; + String gender = userDocument["gender"]; + String imgUrl = userDocument["workerImage"]; + String work = userDocument['WorkerOpted']; + String w_email = userDocument['email']; + String worker_uuid = userDocument['WorkerUID']; + String work_type = userDocument['WorkType']; + String work_opted = userDocument['WorkerOpted']; + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Form( + child: Column(children: [ + Padding( + padding: const EdgeInsets.all(25), + child: CircleAvatar( + radius: 100, + backgroundImage: NetworkImage(imgUrl), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Name : ""$name", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Age : $age", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Gender : $gender", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Experience : $exp year(s)" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Work : $work" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.center, + padding: const EdgeInsets.all(10), + child: Text( + brief , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(10), + child: Text( + "Cost : $cost /-" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(10), + child: TextButton.icon( + onPressed: () { }, + label: Text( + contact , + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + icon: Icon(Icons.call_outlined , color: HexColor('#0B4360')), + ), + ), + + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + showModalBottomSheet( + context: context, + builder: (BuildContext context){ + return Container( + color: HexColor('#ffe6e6'), + padding: const EdgeInsets.all(10), + child: Form( + key: formKey, + child: ListView( + children: [ + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter your address *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: K/202 , Society name/Bungalow name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + flat = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter Landmark *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: Near Seasons mall", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + landmark = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter City and State *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: Pune, Maharashtra", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + state = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + controller: dateInput, + decoration: InputDecoration( + icon: Icon(Icons.calendar_today , color: HexColor('#0B4360')), + labelText: 'Choose Date', + ), + readOnly: true, + onTap: () async{ + DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1950), + //DateTime.now() - not to allow to choose before today. + lastDate: DateTime(2100)); + + if (pickedDate != null) { + print(pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000 + String formattedDate = DateFormat('yyyy-MM-dd').format(pickedDate); + print(formattedDate); //formatted date output using intl package => 2021-03-16 + setState(() { + dateInput.text = formattedDate; //set output date to TextField value. + }); + } else { + } + }, + validator: (value){ + if(value!.isEmpty){ + return "Please choose date"; + } + else{ + return null; + } + }, + onSaved: (value){ + dateInput.text = value!; + }, + ), + + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + controller: timeinput, //editing controller of this TextField + decoration: InputDecoration( + icon: Icon(Icons.timer_outlined , color: HexColor('#0B4360')), //icon of text field + labelText: "Enter Time" //label text of field + ), + readOnly: true, + onTap: () async { + TimeOfDay? pickedTime = await showTimePicker( + initialTime: TimeOfDay.now(), + context: context, + ); + if(pickedTime != null ){ + print(pickedTime.format(context)); //output 10:51 PM + DateTime parsedTime = DateFormat.jm().parse(pickedTime.format(context).toString()); + //converting to DateTime so that we can further format on different pattern. + print(parsedTime); //output 1970-01-01 22:53:00.000 + String formattedTime = DateFormat('HH:mm:ss').format(parsedTime); + print(formattedTime); //output 14:59:00 + //DateFormat() is from intl package, you can format the time on any pattern you need. + setState(() { + timeinput.text = formattedTime; //set the value of text field. + }); + }else{ + print("Time is not selected"); + } + }, + validator: (value){ + if(value!.isEmpty){ + return "Please choose time"; + } + else{ + return null; + } + }, + onSaved: (value){ + timeinput.text = value!; + }, + ), + ), + + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextButton.icon( + onPressed: () { }, + label: Text( + 'Pay '+cost+" when work is completed", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + icon: Icon(Icons.attach_money_outlined , color: HexColor('#0B4360')), + ), + ), + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + if(formKey.currentState!.validate()){ + formKey.currentState!.save(); + String w_approval = 'Not Approved' , payment_sts = 'Not Done' , work_sts = 'Not Started'; + String booking_no = randomAlphaNumeric(8); + + FirestoreServices2.booking(fname, lname,u_email, u_contact, flat, Auth.getUid(), landmark, state, dateInput.text.toString(), timeinput.text.toString(),imgUrl, work , name, uid, w_email ,contact, w_approval, cost, payment_sts, work_sts , text , worker_uuid , booking_no , work_type , work_opted); + Navigator.of(context).pop(); + Navigator.push(context, MaterialPageRoute(builder: (context) => const Booking())); + + } + else{ + showSnacBar(context, "Error"); + } + }, + child: Text( + "Confirm", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + ); + } + ); + + }, + child: Text( + "Book Now", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + + ], + ), + ), + );});}); + + } +} diff --git a/lib/app/AppWorkerList.dart b/lib/app/AppWorkerList.dart new file mode 100644 index 00000000..3b4a0cb7 --- /dev/null +++ b/lib/app/AppWorkerList.dart @@ -0,0 +1,121 @@ +import 'package:budget_worker/AppWorkerData.dart'; +import 'package:budget_worker/showSnacBar.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'CleanWorkerData.dart'; + +class AppWorkerList extends StatelessWidget { + final String text , cost; + const AppWorkerList({Key? key, required this.text, required this.cost}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(text), + ), + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(30), + child: Text( + 'Workers for $text', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 22, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ), + ), + ), + Expanded( + child: SizedBox( + height: 700, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection(text).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasError) { + return const Text('Something went wrong'); + } + if (snapshot.connectionState == ConnectionState.waiting) { + return const Text("Loading"); + } + + return ListView( + shrinkWrap: true, + children: snapshot.data!.docs.map((DocumentSnapshot document){ + Map data = document.data()! as Map; + return Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + ListTile( + title: Text( + data['name'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + onTap: (){ + Navigator.push(context , MaterialPageRoute(builder: (context) => AppWorkerData(text : text , cost : cost , uid : data['uid']))); + + }, + leading: CircleAvatar(backgroundColor: Colors.white60, backgroundImage: NetworkImage(data['workerImage']),radius: 30,), + subtitle: Text( + "${'Experience of '+data['Experience']} year(s)", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + ), + Container( + padding: const EdgeInsets.all(0), + alignment: Alignment.bottomRight, + child: TextButton.icon( + onPressed: () { }, + label: Text( + data['rating'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + icon: Icon(Icons.star , color: HexColor('#0B4360')), + ) + ), + + ],), + ); + }).toList(), + ); + }), + ), + ), + ].reversed.toList(), + ), + ), + ); + } +} diff --git a/lib/app/Booking.dart b/lib/app/Booking.dart new file mode 100644 index 00000000..2523fa40 --- /dev/null +++ b/lib/app/Booking.dart @@ -0,0 +1,305 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_rating_bar/flutter_rating_bar.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'auth.dart'; + +class Booking extends StatefulWidget { + const Booking({Key? key}) : super(key: key); + + @override + State createState() => _BookingState(); +} + +class _BookingState extends State { + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot){ + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var userDocument = snapshot.data!.data(); + String email = userDocument["email"]; + + return Scaffold( + appBar: AppBar( + title: Text( + "Bookings" , style: GoogleFonts.alata( + color: Colors.white, + fontStyle: FontStyle.normal, + ), + ), + ), + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(20), + alignment: Alignment.centerLeft, + child: Text( + 'Your Bookings ', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 21, + ), + ), + ), + Expanded( + child: SizedBox( + height: 700, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection("Booking").where("User_email" , isEqualTo: email).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot){ + if (snapshot.hasError) { + return const Text('Something went wrong'); + } + if (snapshot.connectionState == ConnectionState.waiting) { + return const Text("Loading"); + } + return ListView( + shrinkWrap: true, + children: snapshot.data!.docs.map((DocumentSnapshot document){ + Map db = document.data()! as Map; + String bid = db['bookingId']; + return Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + ListTile( + title: Text( + db['Work'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + + leading: CircleAvatar(backgroundColor: Colors.white60, backgroundImage: NetworkImage(db['Worker_image']), radius: 23,), + subtitle: Text( + db['booking_date'] +", "+ db['booking_time'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 14, + ), + ), + onTap: (){ + setState(() { + showModalBottomSheet( + context: context, + builder: (BuildContext context){ + return Container( + color: HexColor('#ffe6e6'), + padding: const EdgeInsets.all(10), + child: SizedBox( + height: 300, + child: Column( + children: [ + Container( + padding: const EdgeInsets.all(0), + alignment: Alignment.bottomRight, + child: TextButton.icon( + onPressed: () { + + }, + label: Text( + db['Work_sts'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + icon: Icon(Icons.incomplete_circle , color: HexColor('#0B4360')), + ), + ), + if(db['Work_sts'] == "Not Started") ...[ + Container( + padding: const EdgeInsets.all(10), + child: Text( + 'Work has not started yet , status will get updated when the work starts ', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + ), + ], + + Container( + padding: const EdgeInsets.all(10), + child: Text( + '${'Worker Name : '+db['Worker_name']}\nWorker Contact : '+db['Worker_contact'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + ), + + if(db['Work_sts'] == 'Started') ...[ + Text( + db['Worker_name'] + " has started "+db['Work']+ " work", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + Text('After the work gets completed click the complete button below', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + FirebaseFirestore.instance.collection('Booking').doc(bid).update({'Work_sts': 'Completed'}); + }, + child: Text( + 'Complete', + style: GoogleFonts.alata(color: Colors.white), + ) + ) + ], + if(db['Work_sts'] == 'Completed') ...[ + Container( + padding: EdgeInsets.all(10), + child: Text( + '${'${'Please pay '+db['Worker_name']} '+db['Cost']} /-', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ) + ], + if(db['Payment_sts'] == 'Done') ...[ + Container( + padding : const EdgeInsets.all(10), + child : Text( + 'Please rate our worker', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + + Container( + padding : const EdgeInsets.all(10), + child: RatingBar.builder( + initialRating: 3, + minRating: 1, + direction: Axis.horizontal, + allowHalfRating: true, + itemCount: 5, + itemPadding: const EdgeInsets.symmetric(horizontal: 4.0), + itemBuilder : (context , _) => + Icon( + Icons.star , color: HexColor('#0B4360'),), + onRatingUpdate: (rating){ + String comment = ""; + String name = db['UserFname'] + " "+ db['UserLname']; + String email = db['Worker_email']; + String work = db['Work_type']+', '+db['Work_opted']; + String rate = rating.toString(); + + print(rating); + if(rating == 1){ + comment = "Bad"; + FirebaseFirestore.instance.collection("Reviews").doc(db['Booking_No']).set({'worker_name' : name , 'worker_email' : email ,'rating' : rate , 'comment' : comment , 'work' : work}); + FirebaseFirestore.instance.collection('Booking').doc(bid).delete(); + } + if(rating == 2 ){ + comment = "Satisfactory"; + FirebaseFirestore.instance.collection("Reviews").doc(db['Booking_No']).set({'worker_name' : name , 'worker_email' : email ,'rating' : rate , 'comment' : comment , 'work' : work}); + FirebaseFirestore.instance.collection('Booking').doc(bid).delete(); + } + if(rating == 3){ + comment = "Can do better"; + FirebaseFirestore.instance.collection("Reviews").doc(db['Booking_No']).set({'worker_name' : name , 'worker_email' : email ,'rating' : rate , 'comment' : comment , 'work' : work}); + FirebaseFirestore.instance.collection('Booking').doc(bid).delete(); + } + if(rating == 4){ + comment = "Impressive"; + FirebaseFirestore.instance.collection("Reviews").doc(db['Booking_No']).set({'worker_name' : name , 'worker_email' : email ,'rating' : rate , 'comment' : comment , 'work' : work}); + FirebaseFirestore.instance.collection('Booking').doc(bid).delete(); + } + if(rating == 5){ + comment = "Excellent"; + FirebaseFirestore.instance.collection("Reviews").doc(db['Booking_No']).set({'worker_name' : name , 'worker_email' : email ,'rating' : rate , 'comment' : comment , 'work' : work}); + FirebaseFirestore.instance.collection('Booking').doc(bid).delete(); + } + Navigator.of(context).pop(); + }, + ), + ), + ], + if(db['Payment_sts'] == 'Incomplete') ...[ + Container( + padding: EdgeInsets.all(10), + child: Text( + '${'Payment has been incomplete please pay the worker '+ db['Cost']} /-', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + ], + ], + ), + ), + ); + } + ); + }); + }, + ), + ],), + ); + } , ).toList(), + ); + }, + ), + ) + ), + ].reversed.toList(), + ), + ), + ); + }); + } +} diff --git a/lib/app/CleanWorkerData.dart b/lib/app/CleanWorkerData.dart new file mode 100644 index 00000000..2323fd1b --- /dev/null +++ b/lib/app/CleanWorkerData.dart @@ -0,0 +1,491 @@ +import 'package:budget_worker/FirebaseFunctions.dart'; +import 'package:budget_worker/showSnacBar.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:intl/intl.dart'; +import 'package:random_string/random_string.dart'; + +import 'Booking.dart'; +import 'auth.dart'; + +class CleanWorkerData extends StatefulWidget { + final String text , cost , uid ; + + CleanWorkerData({Key? key, required this.text, required this.cost , required this.uid}); + + + @override + State createState() => _CleanWorkerDataState(text , cost , uid); +} + +class _CleanWorkerDataState extends State { + String text , cost , uid; + _CleanWorkerDataState(this.text , this.cost , this.uid); + final formKey = GlobalKey(); + String flat = "" , landmark = " " , state = ""; + TextEditingController dateInput = TextEditingController(); + TextEditingController timeinput = TextEditingController(); + @override + void initState() { + dateInput.text = ""; + timeinput.text = ""; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var doc = snapshot.data!.data(); + var fname = doc['FirstName']; + var lname = doc['LastName']; + var u_contact = doc['contact']; + var u_email = doc['email']; + var id = doc['uid']; + + return StreamBuilder( + stream: FirebaseFirestore.instance.collection(text).doc(uid).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var userDocument = snapshot.data!.data(); + String name = userDocument["name"]; + String contact = userDocument["contact"]; + String exp = userDocument['Experience']; + String brief = userDocument['Brief']; + String age = userDocument["Age"]; + String gender = userDocument["gender"]; + String imgUrl = userDocument["workerImage"]; + String work = userDocument['WorkerOpted']; + String w_email = userDocument['email']; + String worker_uuid = userDocument['WorkerUID']; + String work_type = userDocument['WorkType']; + String work_opted = userDocument['WorkerOpted']; + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Form( + child: Column(children: [ + Padding( + padding: const EdgeInsets.all(25), + child: CircleAvatar( + radius: 100, + backgroundImage: NetworkImage(imgUrl), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Name : ""$name", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Age : $age", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Gender : $gender", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Experience : $exp year(s)" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Work : $work" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.center, + padding: const EdgeInsets.all(10), + child: Text( + brief , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(10), + child: Text( + "Cost : $cost /-" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(10), + child: TextButton.icon( + onPressed: () { }, + label: Text( + contact , + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + icon: Icon(Icons.call_outlined , color: HexColor('#0B4360')), + ), + ), + + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + showModalBottomSheet( + context: context, + builder: (BuildContext context){ + return Container( + color: HexColor('#ffe6e6'), + padding: const EdgeInsets.all(10), + child: Form( + key: formKey, + child: ListView( + children: [ + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter your address *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: K/202 , Society name/Bungalow name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + flat = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter Landmark *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: Near Seasons mall", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + landmark = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter City and State *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: Pune, Maharashtra", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + state = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + controller: dateInput, + decoration: InputDecoration( + icon: Icon(Icons.calendar_today , color: HexColor('#0B4360')), + labelText: 'Choose Date', + ), + readOnly: true, + onTap: () async{ + DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1950), + //DateTime.now() - not to allow to choose before today. + lastDate: DateTime(2100)); + + if (pickedDate != null) { + print(pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000 + String formattedDate = DateFormat('yyyy-MM-dd').format(pickedDate); + print(formattedDate); //formatted date output using intl package => 2021-03-16 + setState(() { + dateInput.text = formattedDate; //set output date to TextField value. + }); + } else { + } + }, + validator: (value){ + if(value!.isEmpty){ + return "Please choose date"; + } + else{ + return null; + } + }, + onSaved: (value){ + dateInput.text = value!; + }, + ), + + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + controller: timeinput, //editing controller of this TextField + decoration: InputDecoration( + icon: Icon(Icons.timer_outlined , color: HexColor('#0B4360')), //icon of text field + labelText: "Enter Time" //label text of field + ), + readOnly: true, + onTap: () async { + TimeOfDay? pickedTime = await showTimePicker( + initialTime: TimeOfDay.now(), + context: context, + ); + if(pickedTime != null ){ + print(pickedTime.format(context)); //output 10:51 PM + DateTime parsedTime = DateFormat.jm().parse(pickedTime.format(context).toString()); + //converting to DateTime so that we can further format on different pattern. + print(parsedTime); //output 1970-01-01 22:53:00.000 + String formattedTime = DateFormat('HH:mm:ss').format(parsedTime); + print(formattedTime); //output 14:59:00 + //DateFormat() is from intl package, you can format the time on any pattern you need. + setState(() { + timeinput.text = formattedTime; //set the value of text field. + }); + }else{ + print("Time is not selected"); + } + }, + validator: (value){ + if(value!.isEmpty){ + return "Please choose time"; + } + else{ + return null; + } + }, + onSaved: (value){ + timeinput.text = value!; + }, + ), + ), + + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextButton.icon( + onPressed: () { }, + label: Text( + 'Pay '+cost+" when work is completed", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + icon: Icon(Icons.attach_money_outlined , color: HexColor('#0B4360')), + ), + ), + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + if(formKey.currentState!.validate()){ + formKey.currentState!.save(); + String w_approval = 'Not Approved' , payment_sts = 'Not Done' , work_sts = 'Not Started'; + String booking_no = randomAlphaNumeric(8); + + FirestoreServices2.booking(fname, lname,u_email, u_contact, flat, Auth.getUid(), landmark, state, dateInput.text.toString(), timeinput.text.toString(),imgUrl, work , name, uid, w_email ,contact, w_approval, cost, payment_sts, work_sts , text , worker_uuid , booking_no , work_type , work_opted); + Navigator.of(context).pop(); + Navigator.push(context, MaterialPageRoute(builder: (context) => const Booking())); + + } + else{ + showSnacBar(context, "Error"); + } + }, + child: Text( + "Confirm", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + ); + } + ); + + }, + child: Text( + "Book Now", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + + ], + + + ), + + ), + + );});}); + + } +} diff --git a/lib/app/CleanWorkerList.dart b/lib/app/CleanWorkerList.dart new file mode 100644 index 00000000..41cba24c --- /dev/null +++ b/lib/app/CleanWorkerList.dart @@ -0,0 +1,120 @@ +import 'package:budget_worker/showSnacBar.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'CleanWorkerData.dart'; + +class CleanWorkerList extends StatelessWidget { + final String text , cost; + const CleanWorkerList({Key? key, required this.text, required this.cost}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(text), + ), + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(30), + child: Text( + 'Workers for $text', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 22, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ), + ), + ), + Expanded( + child: SizedBox( + height: 700, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection(text).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasError) { + return const Text('Something went wrong'); + } + if (snapshot.connectionState == ConnectionState.waiting) { + return const Text("Loading"); + } + + return ListView( + shrinkWrap: true, + children: snapshot.data!.docs.map((DocumentSnapshot document){ + Map data = document.data()! as Map; + return Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + ListTile( + title: Text( + data['name'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + onTap: (){ + Navigator.push(context , MaterialPageRoute(builder: (context) => CleanWorkerData(text : text , cost : cost , uid : data['uid']))); + + }, + leading: CircleAvatar(backgroundColor: Colors.white60, backgroundImage: NetworkImage(data['workerImage']),radius: 30,), + subtitle: Text( + "${'Experience of '+data['Experience']} year(s)", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + ), + Container( + padding: const EdgeInsets.all(0), + alignment: Alignment.bottomRight, + child: TextButton.icon( + onPressed: () { }, + label: Text( + data['rating'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + icon: Icon(Icons.star , color: HexColor('#0B4360')), + ) + ), + + ],), + ); + }).toList(), + ); + }), + ), + ), + ].reversed.toList(), + ), + ), + ); + } +} diff --git a/lib/app/Dashboard.dart b/lib/app/Dashboard.dart new file mode 100644 index 00000000..7230e015 --- /dev/null +++ b/lib/app/Dashboard.dart @@ -0,0 +1,63 @@ +import 'package:budget_worker/HomePage.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'Booking.dart'; +import 'UserAcc.dart'; + +class Dashboard extends StatefulWidget { + const Dashboard({Key? key}) : super(key: key); + + @override + State createState() => _DashboardState(); +} + +class _DashboardState extends State { + int index = 0; + final _screens = [ + const HomePage(), + const Booking(), + const UserAcc(), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: _screens[index], + backgroundColor : HexColor('#ffe6e6'), + + bottomNavigationBar: NavigationBarTheme( + data: NavigationBarThemeData( + indicatorColor: HexColor('#76c7ef'), + labelTextStyle: MaterialStateProperty.all( + const TextStyle(fontSize: 14 , fontWeight: FontWeight.w500 , color: Colors.white), + ), + ), + child: NavigationBar( + height: 60, + backgroundColor: HexColor('#0B4360'), + selectedIndex: index, + onDestinationSelected: (index) => setState(() { + this.index = index; + }), + destinations: const [ + NavigationDestination( + icon: Icon(Icons.home_outlined, color: Colors.white,), + label: "Home", + ), + NavigationDestination( + icon: Icon(Icons.bookmark_border_rounded, color: Colors.white,), + label: "Bookings" , + ), + NavigationDestination( + icon: Icon(Icons.person_outline, color: Colors.white,), + label: "Account" , + ), + ], + ), + ), + ); + } +} + diff --git a/lib/app/ForgotPassword.dart b/lib/app/ForgotPassword.dart new file mode 100644 index 00000000..6acb5d51 --- /dev/null +++ b/lib/app/ForgotPassword.dart @@ -0,0 +1,102 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:lottie/lottie.dart'; + +import 'auth.dart'; + +class ForgotPassword extends StatefulWidget { + const ForgotPassword({Key? key}) : super(key: key); + + @override + State createState() => _ForgotPasswordState(); +} + +class _ForgotPasswordState extends State { + TextEditingController email = TextEditingController(); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(20), + child: Text( + 'Forgot Password ?', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 30, + color: HexColor('#0B4360'), + fontWeight: FontWeight.bold, + fontStyle: FontStyle.normal, + ), + ), + ), + Container( + padding: const EdgeInsets.all(20), + height: 120, + width: 160, + child: Text( + 'We understand that forgetting your password can be frustrating. Let us help you reset it so you can continue using our service hassle-free', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 15, + color: HexColor('#0B4360'), + fontWeight: FontWeight.bold, + fontStyle: FontStyle.normal, + ), + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: Lottie.asset( + 'assets/JSON/bwFP.json', + height: 270.0, + repeat: true, + reverse: true, + animate: true, + ), + ), + + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + keyboardType: TextInputType.emailAddress, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.alternate_email_rounded , color: HexColor('#0B4360'),), + labelText: "Enter Registered Email", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + controller: email, + ), + ), + Container( + height: 90.0, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + Auth.resetPassword(email.text.toString() , context); + }, + child: Text( + "Send Verification Link", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ].reversed.toList(), + ), + ), + ); + } +} diff --git a/lib/app/HomePage.dart b/lib/app/HomePage.dart new file mode 100644 index 00000000..e126fb53 --- /dev/null +++ b/lib/app/HomePage.dart @@ -0,0 +1,354 @@ +import 'package:budget_worker/AppWorkerList.dart'; +import 'package:budget_worker/QuickWorkerList.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'Booking.dart'; +import 'CleanWorkerList.dart'; +import 'auth.dart'; + +class HomePage extends StatefulWidget { + const HomePage({Key? key}) : super(key: key); + + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State { + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var userDocument = snapshot.data!.data(); + String fname = userDocument["FirstName"]; + + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 15, + margin: const EdgeInsets.all(20), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(20), + child: Text( + 'Hi, $fname', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 25, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ), + ), + ),], + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: CupertinoSearchTextField( + backgroundColor: Colors.white, + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.displayLarge, + fontSize: 18, + color: HexColor('#0B4360'), + fontWeight: FontWeight.normal, + fontStyle: FontStyle.normal, + ), + placeholder: 'Search for Cleaning , Massage , Cooking etc..', + placeholderStyle: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.displayLarge, + fontSize: 18, + color: Colors.blueGrey, + fontWeight: FontWeight.normal, + fontStyle: FontStyle.normal, + ), + autocorrect: true, + ), + ), + + Container( + padding: const EdgeInsets.all(25), + child: Text( + "Cleaning & Dusting", + style: GoogleFonts.alata( + fontSize: 20, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + Expanded( + child: SizedBox( + height: 290, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection("Cleaning").snapshots(), + builder: (context , snapshot){ + return ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: snapshot.data?.docs.length, + itemBuilder: (context , index){ + DocumentSnapshot db = snapshot.data?.docs[index] as DocumentSnapshot; + return Container( + width: 235, + padding: const EdgeInsets.all(10), + child: Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + Container( + padding: const EdgeInsets.all(10), + child: Image.network(db['image']), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + db['title'], + style: GoogleFonts.alata( + fontSize: 15, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + db['desc'], + style: GoogleFonts.alata( + fontSize: 14, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w500, + ), + ), + ), + Container( + padding: const EdgeInsets.all(5), + child: TextButton( + onPressed: () { + Navigator.push(context , MaterialPageRoute(builder: (context) => CleanWorkerList(text : db['dbName'] , cost : db['cost']))); + }, + child: Text( + "View", + style: GoogleFonts.alata( + fontSize: 14, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ],), + ), + ); + }, + ); + } + ), + ), + ), + Container( + padding: const EdgeInsets.all(25), + child: Text( + "Appliance Repair", + style: GoogleFonts.alata( + fontSize: 20, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + Expanded( + child: SizedBox( + height: 290, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection("ApplianceRepair").snapshots(), + builder: (context , snapshot){ + return ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: snapshot.data?.docs.length, + itemBuilder: (context , index){ + DocumentSnapshot db = snapshot.data?.docs[index] as DocumentSnapshot; + return Container( + width: 235, + padding: const EdgeInsets.all(10), + child: Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + Container( + padding: const EdgeInsets.all(10), + child: Image.network(db['image']), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + db['title'], + style: GoogleFonts.alata( + fontSize: 15, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + db['desc'], + style: GoogleFonts.alata( + fontSize: 14, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w500, + ), + ), + ), + Container( + padding: const EdgeInsets.all(5), + child: TextButton( + onPressed: () { + Navigator.push(context , MaterialPageRoute(builder: (context) => AppWorkerList(text : db['dbName'] , cost : db['cost']))); + }, + child: Text( + "View", + style: GoogleFonts.alata( + fontSize: 14, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ],), + ), + ); + }, + ); + } + ), + ), + ), + Container( + padding: const EdgeInsets.all(25), + child: Text( + "Quick Home Repair", + style: GoogleFonts.alata( + fontSize: 20, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + Expanded( + child: SizedBox( + height: 290, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection("QuickHomeRepair").snapshots(), + builder: (context , snapshot){ + return ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: snapshot.data?.docs.length, + itemBuilder: (context , index){ + DocumentSnapshot db = snapshot.data?.docs[index] as DocumentSnapshot; + return Container( + width: 235, + padding: const EdgeInsets.all(10), + child: Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + Container( + padding: const EdgeInsets.all(10), + child: Image.network(db['image']), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + db['title'], + style: GoogleFonts.alata( + fontSize: 15, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + db['desc'], + style: GoogleFonts.alata( + fontSize: 14, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w500, + ), + ), + ), + Container( + padding: const EdgeInsets.all(5), + child: TextButton( + onPressed: () { + Navigator.push(context , MaterialPageRoute(builder: (context) => QuickWorkerList(text : db['dbName'] , cost : db['cost']))); + }, + child: Text( + "View", + style: GoogleFonts.alata( + fontSize: 14, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ],), + ), + ); + }, + ); + } + ), + ), + ), + ].reversed.toList(), + ), + ), + );}); + } +} \ No newline at end of file diff --git a/lib/app/LoginScreen.dart b/lib/app/LoginScreen.dart new file mode 100644 index 00000000..025f97eb --- /dev/null +++ b/lib/app/LoginScreen.dart @@ -0,0 +1,186 @@ +import 'package:budget_worker/HomePage.dart'; +import 'package:budget_worker/ForgotPassword.dart'; +import 'package:budget_worker/SignUp.dart'; +import 'package:budget_worker/showSnacBar.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:lottie/lottie.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'auth.dart'; + +class LoginScreen extends StatefulWidget { + const LoginScreen ({Key? key}) : super(key: key); + + @override + State createState() => _LoginScreenState(); +} + + +class _LoginScreenState extends State { + final formKey = GlobalKey(); + String email = "" , password = ""; + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(35), + height: 155, + width: 160, + child: Text( + 'Welcome, you have been missed !', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 30, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ), + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: Lottie.asset( + 'assets/JSON/bwLogin2.json', + height: 270.0, + repeat: true, + reverse: true, + animate: true, + ), + ), + Form( + key: formKey, + child: Column(children: [ + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + keyboardType: TextInputType.emailAddress, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.alternate_email_rounded , color: HexColor('#0B4360'),), + labelText: "Enter Email", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty || !RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)){ + return "Enter Correct Email Address"; + }else{ + return null; + } + }, + onSaved: (value){ + setState(() { + email = value!; + }); + }, + // controller: controller, + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + obscureText: true, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.key_outlined , color: HexColor('#0B4360'),), + labelText: "Enter Password", + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(30), + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + ) + ), + onSaved: (value){ + setState(() { + password = value!; + }); + }, + // controller: controller2, + ), + ), + Container( + padding: const EdgeInsets.all(5), + alignment: Alignment.centerRight, + child: TextButton.icon( + onPressed: () { + setState((){ + Navigator.push(context, MaterialPageRoute(builder: (context) => const ForgotPassword())); + }); + }, + label: Text( + 'Forgot Password ? ', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + textAlign: TextAlign.end, + ), + icon: Icon(Icons.email_outlined , color: HexColor('#0B4360'),), + ), + ), + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + if(formKey.currentState!.validate()){ + //check if form data are valid, + // your process task ahed if all data are valid + formKey.currentState!.save(); + Auth.signinUser(email, password, context); + } + else{ + showSnacBar(context, "Error"); + } + // loginUser(); + }, + child: Text( + "Verify", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + Container( + padding: const EdgeInsets.all(1), + child: const Divider( + color: Colors.grey, + height: 1, + thickness: 1, + ), + ), + Container( + padding: const EdgeInsets.all(1), + child: TextButton( + onPressed: () { + setState((){ + Navigator.push(context, MaterialPageRoute(builder: (context) => const SignUp())); + }); + }, + child: Text( + "Don't have an account yet ? Click here", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + ), + ), + ), + ), + ],), + ), + ].reversed.toList(), + ), + ), + ); + } +} diff --git a/lib/app/QuickWorkerData.dart b/lib/app/QuickWorkerData.dart new file mode 100644 index 00000000..4bffdc7b --- /dev/null +++ b/lib/app/QuickWorkerData.dart @@ -0,0 +1,485 @@ +import 'package:budget_worker/FirebaseFunctions.dart'; +import 'package:budget_worker/showSnacBar.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:intl/intl.dart'; +import 'package:random_string/random_string.dart'; + +import 'Booking.dart'; +import 'auth.dart'; + +class QuickWorkerData extends StatefulWidget { + final String text , cost , uid ; + QuickWorkerData({Key? key, required this.text, required this.cost , required this.uid}); + + @override + State createState() => _QuickWorkerData(text , cost , uid); +} + +class _QuickWorkerData extends State { + String text , cost , uid; + _QuickWorkerData(this.text , this.cost , this.uid); + final formKey = GlobalKey(); + String flat = "" , landmark = " " , state = ""; + TextEditingController dateInput = TextEditingController(); + TextEditingController timeinput = TextEditingController(); + @override + void initState() { + dateInput.text = ""; + timeinput.text = ""; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var doc = snapshot.data!.data(); + var fname = doc['FirstName']; + var lname = doc['LastName']; + var u_contact = doc['contact']; + var u_email = doc['email']; + var id = doc['uid']; + + return StreamBuilder( + stream: FirebaseFirestore.instance.collection(text).doc(uid).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var userDocument = snapshot.data!.data(); + String name = userDocument["name"]; + String contact = userDocument["contact"]; + String exp = userDocument['Experience']; + String brief = userDocument['Brief']; + String age = userDocument["Age"]; + String gender = userDocument["gender"]; + String imgUrl = userDocument["workerImage"]; + String work = userDocument['WorkerOpted']; + String w_email = userDocument['email']; + String worker_uuid = userDocument['WorkerUID']; + String work_type = userDocument['WorkType']; + String work_opted = userDocument['WorkerOpted']; + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Form( + child: Column(children: [ + Padding( + padding: const EdgeInsets.all(25), + child: CircleAvatar( + radius: 100, + backgroundImage: NetworkImage(imgUrl), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Name : ""$name", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Age : $age", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Gender : $gender", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Experience : $exp year(s)" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Work : $work" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.center, + padding: const EdgeInsets.all(10), + child: Text( + brief , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(10), + child: Text( + "Cost : $cost /-" , + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(10), + child: TextButton.icon( + onPressed: () { }, + label: Text( + contact , + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + icon: Icon(Icons.call_outlined , color: HexColor('#0B4360')), + ), + ), + + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + showModalBottomSheet( + context: context, + builder: (BuildContext context){ + return Container( + color: HexColor('#ffe6e6'), + padding: const EdgeInsets.all(10), + child: Form( + key: formKey, + child: ListView( + children: [ + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter your address *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: K/202 , Society name/Bungalow name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + flat = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter Landmark *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: Near Seasons mall", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + landmark = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: Text( + 'Enter City and State *', + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.home_outlined, color: HexColor('#0B4360'),), + labelText: "Eg: Pune, Maharashtra", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty){ + return "Please fill out this field"; + } + else{ + return null; + } + }, + onSaved: (value){ + state = value!; + }, + ), + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + controller: dateInput, + decoration: InputDecoration( + icon: Icon(Icons.calendar_today , color: HexColor('#0B4360')), + labelText: 'Choose Date', + ), + readOnly: true, + onTap: () async{ + DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1950), + //DateTime.now() - not to allow to choose before today. + lastDate: DateTime(2100)); + + if (pickedDate != null) { + print(pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000 + String formattedDate = DateFormat('yyyy-MM-dd').format(pickedDate); + print(formattedDate); //formatted date output using intl package => 2021-03-16 + setState(() { + dateInput.text = formattedDate; //set output date to TextField value. + }); + } else { + } + }, + validator: (value){ + if(value!.isEmpty){ + return "Please choose date"; + } + else{ + return null; + } + }, + onSaved: (value){ + dateInput.text = value!; + }, + ), + + ), + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextFormField( + style: GoogleFonts.alata(), + controller: timeinput, //editing controller of this TextField + decoration: InputDecoration( + icon: Icon(Icons.timer_outlined , color: HexColor('#0B4360')), //icon of text field + labelText: "Enter Time" //label text of field + ), + readOnly: true, + onTap: () async { + TimeOfDay? pickedTime = await showTimePicker( + initialTime: TimeOfDay.now(), + context: context, + ); + if(pickedTime != null ){ + print(pickedTime.format(context)); //output 10:51 PM + DateTime parsedTime = DateFormat.jm().parse(pickedTime.format(context).toString()); + //converting to DateTime so that we can further format on different pattern. + print(parsedTime); //output 1970-01-01 22:53:00.000 + String formattedTime = DateFormat('HH:mm:ss').format(parsedTime); + print(formattedTime); //output 14:59:00 + //DateFormat() is from intl package, you can format the time on any pattern you need. + setState(() { + timeinput.text = formattedTime; //set the value of text field. + }); + }else{ + print("Time is not selected"); + } + }, + validator: (value){ + if(value!.isEmpty){ + return "Please choose time"; + } + else{ + return null; + } + }, + onSaved: (value){ + timeinput.text = value!; + }, + ), + ), + + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.centerLeft, + child: TextButton.icon( + onPressed: () { }, + label: Text( + 'Pay '+cost+" when work is completed", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + icon: Icon(Icons.attach_money_outlined , color: HexColor('#0B4360')), + ), + ), + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + if(formKey.currentState!.validate()){ + formKey.currentState!.save(); + String w_approval = 'Not Approved' , payment_sts = 'Not Done' , work_sts = 'Not Started'; + String booking_no = randomAlphaNumeric(8); + + FirestoreServices2.booking(fname, lname,u_email, u_contact, flat, Auth.getUid(), landmark, state, dateInput.text.toString(), timeinput.text.toString(),imgUrl, work , name, uid, w_email ,contact, w_approval, cost, payment_sts, work_sts , text , worker_uuid , booking_no , work_type , work_opted); + Navigator.of(context).pop(); + Navigator.push(context, MaterialPageRoute(builder: (context) => const Booking())); + + } + else{ + showSnacBar(context, "Error"); + } + }, + child: Text( + "Confirm", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + ); + } + ); + + }, + child: Text( + "Book Now", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + + ], + ), + ), + );});}); + + } +} diff --git a/lib/app/QuickWorkerList.dart b/lib/app/QuickWorkerList.dart new file mode 100644 index 00000000..4faf4530 --- /dev/null +++ b/lib/app/QuickWorkerList.dart @@ -0,0 +1,120 @@ +import 'package:budget_worker/QuickWorkerData.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'CleanWorkerData.dart'; + +class QuickWorkerList extends StatelessWidget { + final String text , cost; + const QuickWorkerList({Key? key, required this.text, required this.cost}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(text), + ), + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(30), + child: Text( + 'Workers for $text', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 22, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ), + ), + ), + Expanded( + child: SizedBox( + height: 700, + child: StreamBuilder( + stream: FirebaseFirestore.instance.collection(text).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasError) { + return const Text('Something went wrong'); + } + if (snapshot.connectionState == ConnectionState.waiting) { + return const Text("Loading"); + } + + return ListView( + shrinkWrap: true, + children: snapshot.data!.docs.map((DocumentSnapshot document){ + Map data = document.data()! as Map; + return Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + ListTile( + title: Text( + data['name'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + onTap: (){ + Navigator.push(context , MaterialPageRoute(builder: (context) => QuickWorkerData(text : text , cost : cost , uid : data['uid']))); + + }, + leading: CircleAvatar(backgroundColor: Colors.white60, backgroundImage: NetworkImage(data['workerImage']),radius: 30,), + subtitle: Text( + "${'Experience of '+data['Experience']} year(s)", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + ), + Container( + padding: const EdgeInsets.all(0), + alignment: Alignment.bottomRight, + child: TextButton.icon( + onPressed: () { }, + label: Text( + data['rating'], + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontSize: 15, + ), + ), + icon: Icon(Icons.star , color: HexColor('#0B4360')), + ) + ), + + ],), + ); + }).toList(), + ); + }), + ), + ), + ].reversed.toList(), + ), + ), + ); + } +} diff --git a/lib/app/SignUp.dart b/lib/app/SignUp.dart new file mode 100644 index 00000000..da047075 --- /dev/null +++ b/lib/app/SignUp.dart @@ -0,0 +1,258 @@ +import 'package:budget_worker/showSnacBar.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:lottie/lottie.dart'; + +import 'LoginScreen.dart'; +import 'auth.dart'; + +class SignUp extends StatefulWidget { + const SignUp({Key? key}) : super(key: key); + + @override + State createState() => _SignUpState(); +} + +class _SignUpState extends State { + final formKey = GlobalKey(); + String email = "" , password = "" , firstname = "" , contact = "" , lastname = "" , imgUrl = "" , age = ""; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Container( + padding: const EdgeInsets.all(30), + child: Text( + 'Sign Up', + style: GoogleFonts.alata( + textStyle: Theme.of(context).textTheme.headlineMedium, + fontSize: 40, + color: HexColor('#0B4360'), + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ), + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: Lottie.asset( + 'assets/JSON/bwSignUp2.json', + height: 270.0, + repeat: true, + reverse: true, + animate: true, + ), + ), + Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15.0), + ), + elevation: 15, + margin: const EdgeInsets.all(30), + shadowColor: HexColor('#0B4360'), + child: Form( + key: formKey, + child : Column(children: [ + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + // focusNode: myFocusNode, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.person_add_alt_1_outlined, color: HexColor('#0B4360'),), + labelText: "Enter First Name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty || !RegExp(r'^[a-z A-Z]+$').hasMatch(value!)){ + //allow upper and lower case alphabets and space + return "Enter Correct Name"; + }else{ + return null; + } + }, + onSaved: (value){ + setState(() { + firstname = value!; + }); + }, + // controller: controller, + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + // focusNode: myFocusNode, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.person_add_alt_1_outlined, color: HexColor('#0B4360'),), + labelText: "Enter Last Name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty || !RegExp(r'^[a-z A-Z]+$').hasMatch(value!)){ + //allow upper and lower case alphabets and space + return "Enter Correct Name"; + }else{ + return null; + } + }, + onSaved: (value){ + setState(() { + lastname = value!; + }); + }, + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + keyboardType: TextInputType.emailAddress, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.alternate_email_rounded , color: HexColor('#0B4360'),), + labelText: "Enter Email Id", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty || !RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)){ + return "Enter Correct Email Address"; + }else{ + return null; + } + }, + onSaved: (value){ + setState(() { + email = value!; + }); + }, + // controller: controller2, + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + keyboardType: TextInputType.phone, + // focusNode: myFocusNode, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.phone, color: HexColor('#0B4360'),), + labelText: "Enter Contact Number", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + validator: (value){ + if(value!.isEmpty || !RegExp(r'^(?:[+0][1-9])?[0-9]{10}$').hasMatch(value)){ + return "Enter Correct Phone Number"; + }else{ + return null; + } + }, + onSaved: (value){ + setState(() { + contact = value!; + }); + }, + // controller: controller, + ), + ), + Container( + padding: const EdgeInsets.all(20), + child: TextFormField( + obscureText: true, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.password , color: HexColor('#0B4360'),), + labelText: "Set a Password", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + onSaved: (value){ + setState(() { + password = value!; + }); + }, + // controller: controller3, + ), + ), + Container( + height: 90.0, + width: 200.0, + padding: const EdgeInsets.all(25), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('0B4360')), + onPressed: (){ + if(formKey.currentState!.validate()){ + //check if form data are valid, + // your process task ahed if all data are valid + formKey.currentState!.save(); + Auth.signupUser(email, password, firstname, lastname, contact, context); + Navigator.push(context, MaterialPageRoute(builder: (context) => const LoginScreen())); + } + else{ + showSnacBar(context, "Error"); + } + }, + child: Text( + "Sign Up", + style: GoogleFonts.alata(), + ), + ), + ), + ],) + ), + ), + Container( + padding: const EdgeInsets.all(1), + child: const Divider( + color: Colors.grey, + height: 1, + thickness: 1, + ), + ), + Container( + padding: const EdgeInsets.all(1), + child: TextButton( + onPressed: () { + setState((){ + Navigator.push(context, MaterialPageRoute(builder: (context) => const LoginScreen())); + }); + }, + child: Text( + "Already have an account ? Login", + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + ), + ), + ), + ), + ].reversed.toList(), + ), + ), + ); + } +} diff --git a/lib/app/UserAcc.dart b/lib/app/UserAcc.dart new file mode 100644 index 00000000..0723090f --- /dev/null +++ b/lib/app/UserAcc.dart @@ -0,0 +1,192 @@ +import 'package:budget_worker/showSnacBar.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'auth.dart'; + +class UserAcc extends StatefulWidget { + const UserAcc({Key? key}) : super(key: key); + + @override + State createState() => _UserAccState(); +} + +class _UserAccState extends State { + final formKey = GlobalKey(); + TextEditingController first_name = TextEditingController(); + TextEditingController last_name = TextEditingController(); + TextEditingController w_contact = TextEditingController(); + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).snapshots(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || !snapshot.data.exists) { + return const Text("No data "); + } + var userDocument = snapshot.data!.data(); + String fname = userDocument["FirstName"]; + String lname = userDocument["LastName"]; + String contact = userDocument["contact"]; + String email = userDocument["email"]; + first_name.text = fname; + last_name.text = lname; + w_contact.text = contact; + + + return Scaffold( + backgroundColor : HexColor('#ffe6e6'), + body: Center( + child: ListView( + shrinkWrap: true, + reverse: true, + children: [ + Form( + key: formKey, + child: Column(children: [ + Container( + padding: const EdgeInsets.all(10), + alignment: Alignment.topLeft, + child: Text( + "Your Account", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 22, + ), + ), + ), + Padding( + padding: const EdgeInsets.all(25), + child: CircleAvatar( + radius: 50, + backgroundColor: HexColor('#0B4360'), + child: Text( + fname.substring(0 , 1).toUpperCase(), + style: GoogleFonts.alata(color: Colors.white , fontSize: 28 , fontWeight: FontWeight.w600), + ), + ), + ), + Card( + color: HexColor('#ffe6e6'), + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + elevation: 8, + margin: const EdgeInsets.all(10), + shadowColor: HexColor('#0B4360'), + child: Column(children: [ + Container( + padding: const EdgeInsets.all(10), + child: TextField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.person_add_alt_1_outlined , color: HexColor('#0B4360'),), + labelText: "First Name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + controller: first_name, + ), + ), + Container( + padding: const EdgeInsets.all(10), + child: TextField( + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.person_add_alt_1_outlined , color: HexColor('#0B4360'),), + labelText: "Last Name", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + controller: last_name, + ), + ), + + Container( + padding: const EdgeInsets.all(10), + child: TextField( + keyboardType: TextInputType.number, + style: GoogleFonts.alata(), + decoration: InputDecoration( + prefixIcon: Icon(Icons.person_add_alt_1_outlined , color: HexColor('#0B4360'),), + labelText: "Conatact", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 3, color: HexColor('#0B4360')), + borderRadius: BorderRadius.circular(30), + ), + ), + controller: w_contact, + ), + ), + + Container( + padding: const EdgeInsets.all(10), + child: Text( + "Email : $email", + // focusNode: myFocusNode, + style: GoogleFonts.alata( + color: HexColor('#0B4360'), + fontStyle: FontStyle.normal, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('#0B4360')), + onPressed: (){ + FirebaseFirestore.instance.collection('UserData').doc(Auth.getUid()).update({ + 'FirstName' : first_name.text.toString(), + 'LastName' : last_name.text.toString(), + 'contact' : w_contact.text.toString(), + }); + showSnacBar(context, "Updated Successfully !"); + }, + child: Text( + "Update", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + Container( + height: 90.0, + width: 380, + padding: const EdgeInsets.all(20), + child: ElevatedButton( + style: ElevatedButton.styleFrom(shape: const StadiumBorder(), backgroundColor: HexColor('#0B4360')), + onPressed: (){ + FirebaseAuth.instance.signOut(); + }, + child: Text( + "Sign out", + style: GoogleFonts.alata(color: Colors.white), + ), + ), + ), + ],), + ), + ],), + ), + ].reversed.toList(), + ), + ), + );}); + } +} diff --git a/lib/app/auth.dart b/lib/app/auth.dart new file mode 100644 index 00000000..060ab35d --- /dev/null +++ b/lib/app/auth.dart @@ -0,0 +1,55 @@ +import 'package:budget_worker/Dashboard.dart'; +import 'package:budget_worker/showSnacBar.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; + +import 'HomePage.dart'; +import 'FirebaseFunctions.dart'; +import 'LoginScreen.dart'; + +class Auth{ + static signupUser(String email , String password , String name, String lastname, String contact ,BuildContext context) async{ + try{ + UserCredential userCredential = await FirebaseAuth.instance.createUserWithEmailAndPassword(email: email, password: password); + await FirebaseAuth.instance.currentUser!.updateDisplayName(name); + await FirebaseAuth.instance.currentUser!.updateEmail(email); + await FirestoreServices.saveUser(name,lastname, email, contact , userCredential.user!.uid); + showSnacBar(context, "Registration Successfull !"); + }on FirebaseAuthException catch (e){ + if(e.code == 'weak-password'){ + showSnacBar(context, "Password provided is too weak"); + } + else if(e.code == 'email-already-in-use'){ + showSnacBar(context, "Email provided already exists"); + } + }catch (e){ + showSnacBar(context, e.toString()); + } + } + + static signinUser(String email , String password , BuildContext context) async{ + try{ + await FirebaseAuth.instance.signInWithEmailAndPassword(email: email, password: password); + showSnacBar(context, "Login Successfull !"); + Navigator.push(context, MaterialPageRoute(builder: (context) => const Dashboard())); + }on FirebaseAuthException catch (e){ + if(e.code == 'user-not-found'){ + showSnacBar(context, "No user found with this email"); + } + else if(e.code == 'wrong-password'){ + showSnacBar(context, "Password did not match"); + } + } + } + static resetPassword(String email , BuildContext context) async { + await FirebaseAuth.instance + .sendPasswordResetEmail(email: email); + showSnacBar(context, "Password request email has been sent to your account "); + Navigator.push(context, MaterialPageRoute(builder: (context) => LoginScreen())); + } + static String? getUid() { + final User? user = FirebaseAuth.instance.currentUser; + final uid = user?.uid.toString(); + return uid; + } +} \ No newline at end of file diff --git a/lib/app/firebase_options.dart b/lib/app/firebase_options.dart new file mode 100644 index 00000000..3b1dc703 --- /dev/null +++ b/lib/app/firebase_options.dart @@ -0,0 +1,83 @@ +// 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: 'AIzaSyD__u2b9ARPzluz6ulvUfdY2stwkL0cCgQ', + appId: '1:555238924748:web:a9820873c4cbf6c11b7d69', + messagingSenderId: '555238924748', + projectId: 'budget-worker', + authDomain: 'budget-worker.firebaseapp.com', + storageBucket: 'budget-worker.appspot.com', + measurementId: 'G-440HYSV5KR', + ); + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyAaVCGMFRAycYTLHz3iieHWUMMaabpz680', + appId: '1:555238924748:android:57df7b02acc9ab711b7d69', + messagingSenderId: '555238924748', + projectId: 'budget-worker', + storageBucket: 'budget-worker.appspot.com', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyAvEQR7ZzlvAjJB0ZJjEjc0Alh9_AcMjd4', + appId: '1:555238924748:ios:f6172705ab3cf78d1b7d69', + messagingSenderId: '555238924748', + projectId: 'budget-worker', + storageBucket: 'budget-worker.appspot.com', + iosClientId: '555238924748-f7nqb54g0mom4dfer2b08ll4s8k2ig6u.apps.googleusercontent.com', + iosBundleId: 'com.example.budgetWorker', + ); + + static const FirebaseOptions macos = FirebaseOptions( + apiKey: 'AIzaSyAvEQR7ZzlvAjJB0ZJjEjc0Alh9_AcMjd4', + appId: '1:555238924748:ios:f6172705ab3cf78d1b7d69', + messagingSenderId: '555238924748', + projectId: 'budget-worker', + storageBucket: 'budget-worker.appspot.com', + iosClientId: '555238924748-f7nqb54g0mom4dfer2b08ll4s8k2ig6u.apps.googleusercontent.com', + iosBundleId: 'com.example.budgetWorker', + ); +} diff --git a/lib/app/main.dart b/lib/app/main.dart new file mode 100644 index 00000000..87481ea3 --- /dev/null +++ b/lib/app/main.dart @@ -0,0 +1,59 @@ +import 'package:budget_worker/Dashboard.dart'; +import 'package:budget_worker/LoginScreen.dart'; +import 'package:budget_worker/firebase_options.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/material.dart'; + +import 'HomePage.dart'; + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); + runApp(MyApp()); +} +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + // This is the theme of your application. + // + // Try running your application with "flutter run". You'll see the + // application has a blue toolbar. Then, without quitting the app, try + // changing the primarySwatch below to Colors.green and then invoke + // "hot reload" (press "r" in the console where you ran "flutter run", + // or simply save your changes to "hot reload" in a Flutter IDE). + // Notice that the counter didn't reset back to zero; the application + // is not restarted. + primarySwatch: Colors.blueGrey, + ), + home: const MainPage(), + ); + } +} + +class MainPage extends StatelessWidget { + const MainPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) => Scaffold( + body: StreamBuilder( + stream: FirebaseAuth.instance.authStateChanges(), + builder: (context , snapshot){ + if(snapshot.hasData){ + return const Dashboard(); + } + else{ + return const LoginScreen(); + } + }, + ), + ); +} \ No newline at end of file diff --git a/lib/app/showSnacBar.dart b/lib/app/showSnacBar.dart new file mode 100644 index 00000000..1a6e658b --- /dev/null +++ b/lib/app/showSnacBar.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +void showSnacBar(BuildContext context , String text){ + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + text, + style: GoogleFonts.alata(), + ) + ) + ); +} \ No newline at end of file diff --git a/lib/auth.dart b/lib/auth.dart new file mode 100644 index 00000000..060ab35d --- /dev/null +++ b/lib/auth.dart @@ -0,0 +1,55 @@ +import 'package:budget_worker/Dashboard.dart'; +import 'package:budget_worker/showSnacBar.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; + +import 'HomePage.dart'; +import 'FirebaseFunctions.dart'; +import 'LoginScreen.dart'; + +class Auth{ + static signupUser(String email , String password , String name, String lastname, String contact ,BuildContext context) async{ + try{ + UserCredential userCredential = await FirebaseAuth.instance.createUserWithEmailAndPassword(email: email, password: password); + await FirebaseAuth.instance.currentUser!.updateDisplayName(name); + await FirebaseAuth.instance.currentUser!.updateEmail(email); + await FirestoreServices.saveUser(name,lastname, email, contact , userCredential.user!.uid); + showSnacBar(context, "Registration Successfull !"); + }on FirebaseAuthException catch (e){ + if(e.code == 'weak-password'){ + showSnacBar(context, "Password provided is too weak"); + } + else if(e.code == 'email-already-in-use'){ + showSnacBar(context, "Email provided already exists"); + } + }catch (e){ + showSnacBar(context, e.toString()); + } + } + + static signinUser(String email , String password , BuildContext context) async{ + try{ + await FirebaseAuth.instance.signInWithEmailAndPassword(email: email, password: password); + showSnacBar(context, "Login Successfull !"); + Navigator.push(context, MaterialPageRoute(builder: (context) => const Dashboard())); + }on FirebaseAuthException catch (e){ + if(e.code == 'user-not-found'){ + showSnacBar(context, "No user found with this email"); + } + else if(e.code == 'wrong-password'){ + showSnacBar(context, "Password did not match"); + } + } + } + static resetPassword(String email , BuildContext context) async { + await FirebaseAuth.instance + .sendPasswordResetEmail(email: email); + showSnacBar(context, "Password request email has been sent to your account "); + Navigator.push(context, MaterialPageRoute(builder: (context) => LoginScreen())); + } + static String? getUid() { + final User? user = FirebaseAuth.instance.currentUser; + final uid = user?.uid.toString(); + return uid; + } +} \ No newline at end of file diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart new file mode 100644 index 00000000..3b1dc703 --- /dev/null +++ b/lib/firebase_options.dart @@ -0,0 +1,83 @@ +// 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: 'AIzaSyD__u2b9ARPzluz6ulvUfdY2stwkL0cCgQ', + appId: '1:555238924748:web:a9820873c4cbf6c11b7d69', + messagingSenderId: '555238924748', + projectId: 'budget-worker', + authDomain: 'budget-worker.firebaseapp.com', + storageBucket: 'budget-worker.appspot.com', + measurementId: 'G-440HYSV5KR', + ); + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyAaVCGMFRAycYTLHz3iieHWUMMaabpz680', + appId: '1:555238924748:android:57df7b02acc9ab711b7d69', + messagingSenderId: '555238924748', + projectId: 'budget-worker', + storageBucket: 'budget-worker.appspot.com', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyAvEQR7ZzlvAjJB0ZJjEjc0Alh9_AcMjd4', + appId: '1:555238924748:ios:f6172705ab3cf78d1b7d69', + messagingSenderId: '555238924748', + projectId: 'budget-worker', + storageBucket: 'budget-worker.appspot.com', + iosClientId: '555238924748-f7nqb54g0mom4dfer2b08ll4s8k2ig6u.apps.googleusercontent.com', + iosBundleId: 'com.example.budgetWorker', + ); + + static const FirebaseOptions macos = FirebaseOptions( + apiKey: 'AIzaSyAvEQR7ZzlvAjJB0ZJjEjc0Alh9_AcMjd4', + appId: '1:555238924748:ios:f6172705ab3cf78d1b7d69', + messagingSenderId: '555238924748', + projectId: 'budget-worker', + storageBucket: 'budget-worker.appspot.com', + iosClientId: '555238924748-f7nqb54g0mom4dfer2b08ll4s8k2ig6u.apps.googleusercontent.com', + iosBundleId: 'com.example.budgetWorker', + ); +} diff --git a/lib/firebase_options.template b/lib/firebase_options.template index 57f5e36d..3b1dc703 100644 --- a/lib/firebase_options.template +++ b/lib/firebase_options.template @@ -1,8 +1,6 @@ -// This is a template of the file generated by FlutterFire CLI. -// Actual file will be .dart extension -// ignore_for_file: type=lint +// 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:firebase_storage/firebase_storage.dart'; import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb, TargetPlatform; @@ -29,7 +27,10 @@ class DefaultFirebaseOptions { case TargetPlatform.macOS: return macos; case TargetPlatform.windows: - return 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 - ' @@ -43,54 +44,40 @@ class DefaultFirebaseOptions { } static const FirebaseOptions web = FirebaseOptions( - apiKey: 'YOUR_API_KEY', - appId: 'YOUR_APP_ID', - messagingSenderId: 'YOUR_MESSAGING_ID', - projectId: 'YOUR_PROJECT_ID', - authDomain: 'YOUR_PROJECT_ID.firebaseapp.com', - storageBucket: 'YOUR_PROJECT_ID.appspot.com', - measurementId: 'YOUR_MEASUREMENT_ID', + apiKey: 'AIzaSyD__u2b9ARPzluz6ulvUfdY2stwkL0cCgQ', + appId: '1:555238924748:web:a9820873c4cbf6c11b7d69', + messagingSenderId: '555238924748', + projectId: 'budget-worker', + authDomain: 'budget-worker.firebaseapp.com', + storageBucket: 'budget-worker.appspot.com', + measurementId: 'G-440HYSV5KR', ); - static const String webClientId = - 'YOUR_APP_ID.apps.googleusercontent.com'; - static const FirebaseOptions android = FirebaseOptions( - apiKey: 'YOUR_APP_ID', - appId: 'YOUR_APP_ID', - messagingSenderId: 'YOUR_MESSAGING_ID', - projectId: 'YOUR_PROJECT_ID', - storageBucket: 'YOUR_PROJECT_ID.appspot.com', + apiKey: 'AIzaSyAaVCGMFRAycYTLHz3iieHWUMMaabpz680', + appId: '1:555238924748:android:57df7b02acc9ab711b7d69', + messagingSenderId: '555238924748', + projectId: 'budget-worker', + storageBucket: 'budget-worker.appspot.com', ); static const FirebaseOptions ios = FirebaseOptions( - apiKey: 'YOUR_API_KEY', - appId: 'YOUR_APP_ID', - messagingSenderId: 'YOUR_MESSAGING_ID', - projectId: 'YOUR_PROJECT_ID', - storageBucket: 'YOUR_PROJECT_ID.appspot.com', - iosBundleId: 'com.example.complete', + apiKey: 'AIzaSyAvEQR7ZzlvAjJB0ZJjEjc0Alh9_AcMjd4', + appId: '1:555238924748:ios:f6172705ab3cf78d1b7d69', + messagingSenderId: '555238924748', + projectId: 'budget-worker', + storageBucket: 'budget-worker.appspot.com', + iosClientId: '555238924748-f7nqb54g0mom4dfer2b08ll4s8k2ig6u.apps.googleusercontent.com', + iosBundleId: 'com.example.budgetWorker', ); static const FirebaseOptions macos = FirebaseOptions( - apiKey: 'YOUR_API_KEY', - appId: 'YOUR_APP_ID', - messagingSenderId: 'YOUR_MESSAGING_ID', - projectId: 'YOUR_PROJECT_ID', - storageBucket: 'YOUR_PROJECT_ID.appspot.com', - iosBundleId: 'com.example.complete', + apiKey: 'AIzaSyAvEQR7ZzlvAjJB0ZJjEjc0Alh9_AcMjd4', + appId: '1:555238924748:ios:f6172705ab3cf78d1b7d69', + messagingSenderId: '555238924748', + projectId: 'budget-worker', + storageBucket: 'budget-worker.appspot.com', + iosClientId: '555238924748-f7nqb54g0mom4dfer2b08ll4s8k2ig6u.apps.googleusercontent.com', + iosBundleId: 'com.example.budgetWorker', ); - - static const FirebaseOptions windows = FirebaseOptions( - apiKey: 'YOUR_API_KEY', - appId: 'YOUR_APP_ID', - messagingSenderId: 'YOUR_MESSAGING_ID', - projectId: 'YOUR_PROJECT_ID', - authDomain: 'YOUR_PROJECT_ID.firebaseapp.com', - storageBucket: 'YOUR_PROJECT_ID.appspot.com', - measurementId: 'YOUR_MEASUREMENT_ID', - ); - - final storage = - FirebaseStorage.instanceFor(bucket: "gs://YOUR_PROJECT_ID.appspot.com"); } diff --git a/lib/main.dart b/lib/main.dart index 30c258f2..87481ea3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,44 +1,59 @@ -// ignore_for_file: inference_failure_on_instance_creation - -import 'package:firebase_core/firebase_core.dart'; -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:get_storage/get_storage.dart'; - -import 'app/routes/app_pages.dart'; -import 'firebase_options.dart'; -import 'services/auth_service.dart'; - -void main() async { - WidgetsFlutterBinding.ensureInitialized(); - await GetStorage.init(); - await Firebase.initializeApp( - options: DefaultFirebaseOptions.currentPlatform, - ); - - runApp( - GetMaterialApp.router( - debugShowCheckedModeBanner: - false, //the debug banner will automatically disappear in prod build - title: 'Application', - initialBinding: BindingsBuilder( - () { - Get.put(AuthService()); - }, - ), - getPages: AppPages.routes, - // routeInformationParser: GetInformationParser( - // // initialRoute: Routes.HOME, - // ), - // routerDelegate: GetDelegate( - // backButtonPopMode: PopMode.History, - // preventDuplicateHandlingMode: - // PreventDuplicateHandlingMode.ReorderRoutes, - // ), - theme: ThemeData( - highlightColor: Colors.black.withOpacity(0.5), - bottomSheetTheme: - const BottomSheetThemeData(surfaceTintColor: Colors.blue)), - ), - ); -} +import 'package:budget_worker/Dashboard.dart'; +import 'package:budget_worker/LoginScreen.dart'; +import 'package:budget_worker/firebase_options.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/material.dart'; + +import 'HomePage.dart'; + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); + runApp(MyApp()); +} +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + // This is the theme of your application. + // + // Try running your application with "flutter run". You'll see the + // application has a blue toolbar. Then, without quitting the app, try + // changing the primarySwatch below to Colors.green and then invoke + // "hot reload" (press "r" in the console where you ran "flutter run", + // or simply save your changes to "hot reload" in a Flutter IDE). + // Notice that the counter didn't reset back to zero; the application + // is not restarted. + primarySwatch: Colors.blueGrey, + ), + home: const MainPage(), + ); + } +} + +class MainPage extends StatelessWidget { + const MainPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) => Scaffold( + body: StreamBuilder( + stream: FirebaseAuth.instance.authStateChanges(), + builder: (context , snapshot){ + if(snapshot.hasData){ + return const Dashboard(); + } + else{ + return const LoginScreen(); + } + }, + ), + ); +} \ No newline at end of file diff --git a/lib/showSnacBar.dart b/lib/showSnacBar.dart new file mode 100644 index 00000000..1a6e658b --- /dev/null +++ b/lib/showSnacBar.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +void showSnacBar(BuildContext context , String text){ + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + text, + style: GoogleFonts.alata(), + ) + ) + ); +} \ No newline at end of file