From 8b0c44e35b82c47ecca77145aeff058a893bc1db Mon Sep 17 00:00:00 2001 From: David <1920881@users.noreply.github.com> Date: Tue, 20 Jun 2023 03:23:54 +0200 Subject: [PATCH] Search Companies Search for Jobs --- android/app/src/main/AndroidManifest.xml | 20 ++-- lib/Search/profile_company.dart | 79 ++++++++-------- lib/Search/search_companies.dart | 111 +++++++++++++++++++---- lib/Search/search_job.dart | 99 +++++++++++++++++++- lib/Widgets/all_companies_widget.dart | 103 +++++++++++++++++++++ lib/Widgets/bottom_nav_bar.dart | 12 ++- lib/Widgets/comments_widget.dart | 7 +- 7 files changed, 356 insertions(+), 75 deletions(-) create mode 100644 lib/Widgets/all_companies_widget.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 9a89aa4..0279719 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,23 @@ - - - + + + + + + android:label="cpd_ss23" + android:name="${applicationName}" + android:icon="@mipmap/ic_launcher"> createState() => _ProfileScreenState(); @@ -63,7 +62,7 @@ class _ProfileScreenState extends State { final DocumentSnapshot userDoc = await FirebaseFirestore.instance .collection('users') - .doc(widget.userId) + .doc(widget.userID) .get(); if (userDoc.exists) { @@ -84,7 +83,7 @@ class _ProfileScreenState extends State { User? user = _auth.currentUser; final _uid = user!.uid; setState(() { - _isSameUser = _uid == widget.userId; + _isSameUser = _uid == widget.userID; }); } else { print('User not found'); @@ -119,7 +118,7 @@ class _ProfileScreenState extends State { // Update data in Firebase if (_isSameUser) { - _firestore.collection('users').doc(widget.userId).update({ + _firestore.collection('users').doc(widget.userID).update({ 'name': name, 'email': email, 'phone': phoneNumber, @@ -136,7 +135,7 @@ class _ProfileScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text('Profile'), + title: const Text('Profile'), actions: [ if (_isSameUser) ElevatedButton( @@ -150,7 +149,7 @@ class _ProfileScreenState extends State { Colors.white, ), padding: MaterialStateProperty.all( - EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), + const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), ), shape: MaterialStateProperty.all( RoundedRectangleBorder( @@ -162,7 +161,7 @@ class _ProfileScreenState extends State { if (!_isSameUser && email != null) IconButton( onPressed: _sendEmail, - icon: Icon(Icons.mail), + icon: const Icon(Icons.mail), ), ], ), @@ -188,85 +187,85 @@ class _ProfileScreenState extends State { SingleChildScrollView( child: Column( children: [ - SizedBox(height: 40), + const SizedBox(height: 40), Container( - width: MediaQuery.of(context).size.width , - height: MediaQuery.of(context).size.width , - decoration: BoxDecoration( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.width, + decoration: const BoxDecoration( shape: BoxShape.circle, ), child: ClipOval( child: imageUrl != null ? Image.network( - imageUrl!, - fit: BoxFit.cover, - ) + imageUrl!, + fit: BoxFit.cover, + ) : Image.asset( - 'assets/images/signup.png', - fit: BoxFit.cover, - ), + 'assets/images/signup.png', + fit: BoxFit.cover, + ), ), ), - SizedBox(height: 24), + const SizedBox(height: 24), Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( + const Text( 'Name:', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 18, ), ), - SizedBox(height: 4), + const SizedBox(height: 4), _isEditing && _isSameUser ? TextFormField( - controller: _nameController, - ) + controller: _nameController, + ) : Text(name ?? ''), - SizedBox(height: 16), - Text( + const SizedBox(height: 16), + const Text( 'Email:', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 18, ), ), - SizedBox(height: 4), + const SizedBox(height: 4), _isEditing && _isSameUser ? TextFormField( - controller: _emailController, - ) + controller: _emailController, + ) : Text(email ?? ''), - SizedBox(height: 16), - Text( + const SizedBox(height: 16), + const Text( 'Phone Number:', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 18, ), ), - SizedBox(height: 4), + const SizedBox(height: 4), _isEditing && _isSameUser ? TextFormField( - controller: _phoneNumberController, - ) + controller: _phoneNumberController, + ) : Text(phoneNumber ?? ''), - SizedBox(height: 16), - Text( + const SizedBox(height: 16), + const Text( 'Location:', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 18, ), ), - SizedBox(height: 4), + const SizedBox(height: 4), _isEditing && _isSameUser ? TextFormField( - controller: _locationController, - ) + controller: _locationController, + ) : Text(location ?? ''), ], ), @@ -277,7 +276,7 @@ class _ProfileScreenState extends State { if (_isLoading) Container( color: Colors.black.withOpacity(0.5), - child: Center( + child: const Center( child: CircularProgressIndicator(), ), ), diff --git a/lib/Search/search_companies.dart b/lib/Search/search_companies.dart index 73fd997..21cb0a7 100644 --- a/lib/Search/search_companies.dart +++ b/lib/Search/search_companies.dart @@ -1,39 +1,114 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:cpd_ss23/Widgets/all_companies_widget.dart'; import 'package:cpd_ss23/Widgets/bottom_nav_bar.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; class AllWorkersScreen extends StatefulWidget { - @override State createState() => _AllWorkersScreenState(); } class _AllWorkersScreenState extends State { + final TextEditingController _searchQueryController = TextEditingController(); + String searchQuery = 'Search Query'; + + Widget _buildSearchField() { + return TextField( + controller: _searchQueryController, + autocorrect: true, + decoration: const InputDecoration( + hintText: "Search for companies...", + border: InputBorder.none, + hintStyle: TextStyle(color: Colors.white), + ), + style: const TextStyle(color: Colors.white, fontSize: 16.0), + onChanged: (query) => updateSearchQuery(query), + ); + } + + List _buildActions() { + return [ + IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + _clearSearchQuery(); + }, + ) + ]; + } + + void _clearSearchQuery() { + setState(() { + _searchQueryController.clear(); + updateSearchQuery(""); + }); + } + + void updateSearchQuery(String newQuery) { + setState(() { + searchQuery = newQuery; + print(searchQuery); + }); + } + @override Widget build(BuildContext context) { return Container( decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Colors.cyan, Colors.white60], - begin: Alignment.centerLeft, - end: Alignment.centerRight, - stops: [0.2, 0.9], - ) + gradient: LinearGradient( + colors: [Colors.cyan, Colors.white60], + begin: Alignment.centerLeft, + end: Alignment.centerRight, + stops: [0.2, 0.9], + ) ), child: Scaffold( - bottomNavigationBar: BottomNavigationBarForApp(indexNum: 1,), + bottomNavigationBar: BottomNavigationBarForApp( + indexNum: 1, + ), backgroundColor: Colors.transparent, appBar: AppBar( backgroundColor: Colors.cyan, - title: const Text('All Workers Screen'), - actions: [ - IconButton( - icon: const Icon(Icons.search), - onPressed: () { - // Action when the search icon is clicked - }, - ), - ], + automaticallyImplyLeading: false, + title: _buildSearchField(), + actions: _buildActions(), + ), + body: StreamBuilder( + stream: FirebaseFirestore.instance + .collection("users") + .where("name", isGreaterThanOrEqualTo: searchQuery) + .snapshots(), + builder: (context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center( + child: CircularProgressIndicator(), + ); + } else if (snapshot.connectionState == ConnectionState.active) { + if (snapshot.data!.docs.isNotEmpty) { + return ListView.builder( + itemCount: snapshot.data!.docs.length, + itemBuilder: (BuildContext context, int index) { + return AllWorkersWidget( + userID: snapshot.data!.docs[index]["id"], + userName: snapshot.data!.docs[index]["name"], + userEmail: snapshot.data!.docs[index]["email"], + phoneNumber: snapshot.data!.docs[index]["phone"], + userImageUrl: snapshot.data!.docs[index]["userImage"], + ); + }); + } else { + return const Center( + child: Text("There is no user."), + ); + } + } + return const Center( + child: Text( + "Something went wrong", + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30), + ), + ); + }, ), ), ); diff --git a/lib/Search/search_job.dart b/lib/Search/search_job.dart index 38ff14b..9c0be22 100644 --- a/lib/Search/search_job.dart +++ b/lib/Search/search_job.dart @@ -1,11 +1,57 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:cpd_ss23/Widgets/job_widget.dart'; import 'package:flutter/material.dart'; +import '../jobs/jobs_screen.dart'; + class SearchScreen extends StatefulWidget { @override State createState() => _SearchScreenState(); } class _SearchScreenState extends State { + final TextEditingController _searchQueryController = TextEditingController(); + String searchQuery = 'Search Query'; + + Widget _buildSearchField() { + return TextField( + controller: _searchQueryController, + autocorrect: true, + decoration: const InputDecoration( + hintText: "Search for jobs...", + border: InputBorder.none, + hintStyle: TextStyle(color: Colors.white), + ), + style: const TextStyle(color: Colors.white, fontSize: 16.0), + onChanged: (query) => updateSearchQuery(query), + ); + } + + List _buildActions() { + return [ + IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + _clearSearchQuery(); + }, + ) + ]; + } + + void _clearSearchQuery() { + setState(() { + _searchQueryController.clear(); + updateSearchQuery(""); + }); + } + + void updateSearchQuery(String newQuery) { + setState(() { + searchQuery = newQuery; + print(searchQuery); + }); + } + @override Widget build(BuildContext context) { return Container( @@ -18,7 +64,7 @@ class _SearchScreenState extends State { child: Scaffold( backgroundColor: Colors.transparent, appBar: AppBar( - title: const Text("Search Job Screen"), + title: _buildSearchField(), centerTitle: true, flexibleSpace: Container( decoration: const BoxDecoration( @@ -28,6 +74,57 @@ class _SearchScreenState extends State { end: Alignment.centerRight, stops: [0.2, 0.9])), ), + leading: IconButton( + onPressed: () { + Navigator.pushReplacement(context, + MaterialPageRoute(builder: (context) => JobScreen())); + }, + icon: const Icon(Icons.arrow_back), + ), + actions: _buildActions(), + ), + body: StreamBuilder>>( + stream: FirebaseFirestore.instance + .collection("jobs") + .where("jobTitle", isGreaterThanOrEqualTo: searchQuery) + .where("recruitment", isEqualTo: true) + .snapshots(), + builder: (context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center( + child: CircularProgressIndicator(), + ); + } else if (snapshot.connectionState == ConnectionState.active) { + if (snapshot.data?.docs.isNotEmpty == true) { + return ListView.builder( + itemCount: snapshot.data?.docs.length, + itemBuilder: (BuildContext context, int index) { + return JobWidget( + jobTitle: snapshot.data?.docs[index]["jobTitle"], + jobDescription: snapshot.data?.docs[index] + ["jobDescription"], + jobId: snapshot.data?.docs[index]["jobId"], + uploadedBy: snapshot.data?.docs[index]["uploadedBy"], + userImage: snapshot.data?.docs[index]["userImage"], + name: snapshot.data?.docs[index]["name"], + recruitment: snapshot.data?.docs[index]["recruitment"], + email: snapshot.data?.docs[index]["email"], + location: snapshot.data?.docs[index]["location"]); + }, + ); + } else { + return const Center( + child: Text("There is no Job"), + ); + } + } + return const Center( + child: Text( + "Something went wrong", + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30.0), + ), + ); + }, ), ), ); diff --git a/lib/Widgets/all_companies_widget.dart b/lib/Widgets/all_companies_widget.dart new file mode 100644 index 0000000..a3e5db5 --- /dev/null +++ b/lib/Widgets/all_companies_widget.dart @@ -0,0 +1,103 @@ +import 'package:cpd_ss23/Search/profile_company.dart'; +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher_string.dart'; + +class AllWorkersWidget extends StatefulWidget { + final String userID; + final String userName; + final String userEmail; + final String phoneNumber; + final String userImageUrl; + + const AllWorkersWidget({ + required this.userID, + required this.userName, + required this.userEmail, + required this.phoneNumber, + required this.userImageUrl, + }); + + @override + State createState() => _AllWorkersWidgetState(); +} + +class _AllWorkersWidgetState extends State { + void _mailTo() async { + var mailUrl = "mailto: ${widget.userEmail}"; + print("widget.userEmail ${widget.userEmail}"); + + if (await canLaunchUrlString(mailUrl)) { + await launchUrlString(mailUrl); + } else { + print("error"); + throw "Error Occured"; + } + } + + @override + Widget build(BuildContext context) { + return Card( + elevation: 8, + color: Colors.white10, + margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 6), + child: ListTile( + onTap: () { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => ProfileScreen(userID: widget.userID))); + }, + contentPadding: + const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + leading: Container( + padding: const EdgeInsets.only(right: 12), + decoration: const BoxDecoration( + border: Border( + right: BorderSide(width: 1), + ), + ), + child: CircleAvatar( + backgroundColor: Colors.transparent, + radius: 20, + child: Image.network(widget.userImageUrl == null + ? "https://st4.depositphotos.com/4329009/19956/v/600/depositphotos_199564354-stock-illustration-creative-vector-illustration-default-avatar.jpg" + : widget.userImageUrl), + ), + ), + title: Text( + widget.userName, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + subtitle: const Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Visit Profile", + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: Colors.grey, + ), + ) + ], + ), + trailing: IconButton( + icon: const Icon( + Icons.mail_outline, + size: 30, + color: Colors.grey, + ), + onPressed: () { + _mailTo(); + }, + ), + ), + ); + } +} diff --git a/lib/Widgets/bottom_nav_bar.dart b/lib/Widgets/bottom_nav_bar.dart index 65bf364..5a0d466 100644 --- a/lib/Widgets/bottom_nav_bar.dart +++ b/lib/Widgets/bottom_nav_bar.dart @@ -5,6 +5,7 @@ import 'package:cpd_ss23/user_state.dart'; import 'package:curved_navigation_bar/curved_navigation_bar.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; + import '../jobs/jobs_screen.dart'; class BottomNavigationBarForApp extends StatelessWidget { @@ -94,11 +95,12 @@ class BottomNavigationBarForApp extends StatelessWidget { } else if (index == 2){ Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => UploadJobNow())); } else if (index == 3){ - final FirebaseAuth _auth=FirebaseAuth.instance; - final User? user = _auth.currentUser; - final String uid = user!.uid; - Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => ProfileScreen(userId: uid))); - } + final FirebaseAuth _auth = FirebaseAuth.instance; + final User? user = _auth.currentUser; + final String uid = user!.uid; + Navigator.pushReplacement(context, + MaterialPageRoute(builder: (_) => ProfileScreen(userID: uid))); + } else if (index == 4){ _logout(context); } diff --git a/lib/Widgets/comments_widget.dart b/lib/Widgets/comments_widget.dart index f5e61cd..c885755 100644 --- a/lib/Widgets/comments_widget.dart +++ b/lib/Widgets/comments_widget.dart @@ -1,5 +1,4 @@ import 'package:cpd_ss23/Search/profile_company.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class CommentWidget extends StatefulWidget { @@ -26,7 +25,11 @@ class _CommentWidgetState extends State { Widget build(BuildContext context) { return InkWell( onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context)=> ProfileScreen(userId: widget.commenterId))); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ProfileScreen(userID: widget.commenterId))); }, child: Container( decoration: BoxDecoration(