parent
094fa115c7
commit
4d04499dff
|
@ -1,6 +1,7 @@
|
|||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:cpd_ss23/jobs/job_details.dart';
|
||||
import 'package:cpd_ss23/services/global_methods.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -84,7 +85,15 @@ class _JobWidgetState extends State<JobWidget> {
|
|||
elevation: 8,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
|
||||
child: ListTile(
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
Navigator.pushReplacement(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => JobDetailsScreen(
|
||||
uploadedBy: widget.uploadedBy,
|
||||
jobID: widget.jobId,
|
||||
)));
|
||||
},
|
||||
onLongPress: () {
|
||||
_deleteDialog();
|
||||
},
|
||||
|
|
|
@ -0,0 +1,599 @@
|
|||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:cpd_ss23/jobs/jobs_screen.dart';
|
||||
import 'package:cpd_ss23/services/global_methods.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
class JobDetailsScreen extends StatefulWidget {
|
||||
final String uploadedBy;
|
||||
final String jobID;
|
||||
|
||||
const JobDetailsScreen({required this.uploadedBy, required this.jobID});
|
||||
|
||||
@override
|
||||
State<JobDetailsScreen> createState() => _JobDetailsScreenState();
|
||||
}
|
||||
|
||||
class _JobDetailsScreenState extends State<JobDetailsScreen> {
|
||||
final FirebaseAuth _auth = FirebaseAuth.instance;
|
||||
|
||||
final TextEditingController _commentController = TextEditingController();
|
||||
bool _isCommenting = false;
|
||||
String? authorName;
|
||||
String? userImageUrl;
|
||||
String? jobCategory;
|
||||
String? jobDescription;
|
||||
String? jobTitle;
|
||||
bool? recruitment;
|
||||
Timestamp? postedDateTimeStamp;
|
||||
Timestamp? deadlineDateTimeStamp;
|
||||
String? postedDate;
|
||||
String? deadlineDate;
|
||||
String? locationCompany = "";
|
||||
String? emailCompany = "";
|
||||
int applicants = 0;
|
||||
bool isDeadlineAvailable = false;
|
||||
|
||||
void getJobData() async {
|
||||
final DocumentSnapshot userDoc = await FirebaseFirestore.instance
|
||||
.collection("users")
|
||||
.doc(widget.uploadedBy)
|
||||
.get();
|
||||
if (userDoc == null) {
|
||||
return;
|
||||
} else {
|
||||
setState(() {
|
||||
authorName = userDoc.get("name");
|
||||
userImageUrl = userDoc.get("userImage");
|
||||
});
|
||||
}
|
||||
final DocumentSnapshot jobDatabase = await FirebaseFirestore.instance
|
||||
.collection("jobs")
|
||||
.doc(widget.jobID)
|
||||
.get();
|
||||
if (jobDatabase == null) {
|
||||
return;
|
||||
} else {
|
||||
setState(() {
|
||||
jobTitle = jobDatabase.get("jobTitle");
|
||||
jobDescription = jobDatabase.get("jobDescription");
|
||||
recruitment = jobDatabase.get("recruitment");
|
||||
emailCompany = jobDatabase.get("email");
|
||||
locationCompany = jobDatabase.get("location");
|
||||
applicants = jobDatabase.get("applicants");
|
||||
postedDateTimeStamp = jobDatabase.get("createdAt");
|
||||
deadlineDateTimeStamp = jobDatabase.get("deadlineDateTimeStamp");
|
||||
deadlineDate = jobDatabase.get("deadlineDate");
|
||||
var postDate = postedDateTimeStamp!.toDate();
|
||||
postedDate = "${postDate.year}-${postDate.month}-${postDate.day}";
|
||||
});
|
||||
var date = deadlineDateTimeStamp!.toDate();
|
||||
isDeadlineAvailable = date.isAfter(DateTime.now());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
getJobData();
|
||||
}
|
||||
|
||||
Widget dividerWidget() {
|
||||
return const Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Divider(
|
||||
thickness: 1,
|
||||
color: Colors.grey,
|
||||
),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
applyForJob() {
|
||||
//TODO Mail senden funktioniert noch nicht
|
||||
final Uri params = Uri(
|
||||
scheme: "mailto",
|
||||
path: emailCompany,
|
||||
query:
|
||||
"subject=Applying for $jobTitle&body=Hello, please attach Resume CV file",
|
||||
);
|
||||
final url = params.toString();
|
||||
launchUrlString(url);
|
||||
addNewApplicants();
|
||||
}
|
||||
|
||||
void addNewApplicants() async {
|
||||
var docRef =
|
||||
FirebaseFirestore.instance.collection("jobs").doc(widget.jobID);
|
||||
docRef.update({
|
||||
"applicants": applicants + 1,
|
||||
});
|
||||
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
@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],
|
||||
)),
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
size: 40,
|
||||
color: Colors.white,
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pushReplacement(
|
||||
context, MaterialPageRoute(builder: (context) => JobScreen()));
|
||||
},
|
||||
)),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Card(
|
||||
color: Colors.black54,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4),
|
||||
child: Text(
|
||||
jobTitle == null ? "" : jobTitle!,
|
||||
maxLines: 3,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 30,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
height: 60,
|
||||
width: 60,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color: Colors.grey,
|
||||
),
|
||||
shape: BoxShape.rectangle,
|
||||
image: DecorationImage(
|
||||
image: NetworkImage(
|
||||
userImageUrl == null
|
||||
? "https://img.myloview.de/bilder/avatar-icon-vector-male-user-person-profile-symbol-in-flat-color-glyph-pictogram-illustration-700-163956247.jpg"
|
||||
: userImageUrl!,
|
||||
),
|
||||
fit: BoxFit.fill,
|
||||
)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 10.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
authorName == null ? "" : authorName!,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Text(
|
||||
locationCompany!,
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
dividerWidget(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
applicants.toString(),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 6,
|
||||
),
|
||||
const Text(
|
||||
"Applicants",
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
const Icon(
|
||||
Icons.how_to_reg_sharp,
|
||||
color: Colors.grey,
|
||||
)
|
||||
],
|
||||
),
|
||||
FirebaseAuth.instance.currentUser!.uid !=
|
||||
widget.uploadedBy
|
||||
? Container()
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
dividerWidget(),
|
||||
const Text(
|
||||
"Recruitment",
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
User? user = _auth.currentUser;
|
||||
final _uid = user!.uid;
|
||||
if (_uid == widget.uploadedBy) {
|
||||
try {
|
||||
FirebaseFirestore.instance
|
||||
.collection("jobs")
|
||||
.doc(widget.jobID)
|
||||
.update(
|
||||
{"recruitment": true});
|
||||
} catch (error) {
|
||||
GlobalMethod.showErrorDialog(
|
||||
error:
|
||||
"Action cannot be performed",
|
||||
ctx: context);
|
||||
}
|
||||
} else {
|
||||
GlobalMethod.showErrorDialog(
|
||||
error:
|
||||
"You cannot perform this action",
|
||||
ctx: context);
|
||||
}
|
||||
getJobData();
|
||||
},
|
||||
child: const Text(
|
||||
"ON",
|
||||
style: TextStyle(
|
||||
fontStyle: FontStyle.italic,
|
||||
color: Colors.black,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
Opacity(
|
||||
opacity: recruitment == true ? 1 : 0,
|
||||
child: const Icon(
|
||||
Icons.check_box,
|
||||
color: Colors.green,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 40,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
User? user = _auth.currentUser;
|
||||
final _uid = user!.uid;
|
||||
if (_uid == widget.uploadedBy) {
|
||||
try {
|
||||
FirebaseFirestore.instance
|
||||
.collection("jobs")
|
||||
.doc(widget.jobID)
|
||||
.update(
|
||||
{"recruitment": false});
|
||||
} catch (error) {
|
||||
GlobalMethod.showErrorDialog(
|
||||
error:
|
||||
"Action cannot be performed",
|
||||
ctx: context);
|
||||
}
|
||||
} else {
|
||||
GlobalMethod.showErrorDialog(
|
||||
error:
|
||||
"You cannot perform this action",
|
||||
ctx: context);
|
||||
}
|
||||
getJobData();
|
||||
},
|
||||
child: const Text(
|
||||
"OFF",
|
||||
style: TextStyle(
|
||||
fontStyle: FontStyle.italic,
|
||||
color: Colors.black,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
Opacity(
|
||||
opacity: recruitment == false ? 1 : 0,
|
||||
child: const Icon(
|
||||
Icons.check_box,
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
dividerWidget(),
|
||||
const Text(
|
||||
"Job Description",
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Text(
|
||||
jobDescription == null ? "" : jobDescription!,
|
||||
textAlign: TextAlign.justify,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
dividerWidget(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Card(
|
||||
color: Colors.black54,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Center(
|
||||
child: Text(
|
||||
isDeadlineAvailable
|
||||
? "Actively Recruiting, Send CV/Resume:"
|
||||
: "Deadline Passed away.",
|
||||
style: TextStyle(
|
||||
color: isDeadlineAvailable
|
||||
? Colors.green
|
||||
: Colors.red,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
Center(
|
||||
child: MaterialButton(
|
||||
onPressed: () {
|
||||
applyForJob();
|
||||
},
|
||||
color: Colors.blueAccent,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(13),
|
||||
),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 14),
|
||||
child: Text(
|
||||
"Easy Apply Now",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
dividerWidget(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
"Uploaded on:",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
postedDate == null ? "" : postedDate!,
|
||||
style: const TextStyle(
|
||||
color: Colors.grey,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
"Deadline:",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
deadlineDate == null ? "" : deadlineDate!,
|
||||
style: const TextStyle(
|
||||
color: Colors.grey,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
dividerWidget(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(4.0),
|
||||
child: Card(
|
||||
color: Colors.black54,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AnimatedSwitcher(
|
||||
duration: Duration(
|
||||
milliseconds: 500,
|
||||
),
|
||||
child: _isCommenting
|
||||
? Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: TextField(
|
||||
controller: _commentController,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
maxLength: 200,
|
||||
keyboardType: TextInputType.text,
|
||||
maxLines: 6,
|
||||
decoration: InputDecoration(
|
||||
filled: true,
|
||||
fillColor: Theme.of(context)
|
||||
.scaffoldBackgroundColor,
|
||||
enabledBorder:
|
||||
const UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.white),
|
||||
),
|
||||
focusedBorder:
|
||||
const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.pink),
|
||||
)),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(
|
||||
horizontal: 8),
|
||||
child: MaterialButton(
|
||||
onPressed: () {},
|
||||
color: Colors.blueAccent,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(8),
|
||||
),
|
||||
child: const Text(
|
||||
"Post",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
child: const Text("Cancel"),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
Icons.add_comment,
|
||||
color: Colors.blueAccent,
|
||||
size: 40,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
Icons.arrow_drop_down_circle,
|
||||
color: Colors.blueAccent,
|
||||
size: 40,
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
37
pubspec.yaml
37
pubspec.yaml
|
@ -1,39 +1,17 @@
|
|||
name: cpd_ss23
|
||||
description: A new Flutter project.
|
||||
# The following line prevents the package from being accidentally published to
|
||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||
|
||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
|
||||
# The following defines the version and build number for your application.
|
||||
# A version number is three numbers separated by dots, like 1.2.43
|
||||
# followed by an optional build number separated by a +.
|
||||
# Both the version and the builder number may be overridden in flutter
|
||||
# build by specifying --build-name and --build-number, respectively.
|
||||
# In Android, build-name is used as versionName while build-number used as versionCode.
|
||||
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
|
||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0-378.0.dev <4.0.0'
|
||||
|
||||
# Dependencies specify other packages that your package needs in order to work.
|
||||
# To automatically upgrade your package dependencies to the latest versions
|
||||
# consider running `flutter pub upgrade --major-versions`. Alternatively,
|
||||
# dependencies can be manually updated by changing the version numbers below to
|
||||
# the latest version available on pub.dev. To see which dependencies have newer
|
||||
# versions available, run `flutter pub outdated`.
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.2
|
||||
cached_network_image: ^3.2.3
|
||||
image_picker: ^0.8.7+3
|
||||
|
@ -54,25 +32,12 @@ dev_dependencies:
|
|||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
# The "flutter_lints" package below contains a set of recommended lints to
|
||||
# encourage good coding practices. The lint set provided by the package is
|
||||
# activated in the `analysis_options.yaml` file located at the root of your
|
||||
# package. See that file for information about deactivating specific lint
|
||||
# rules and activating additional ones.
|
||||
flutter_lints: ^2.0.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
# The following section is specific to Flutter packages.
|
||||
flutter:
|
||||
|
||||
# The following line ensures that the Material Icons font is
|
||||
# included with your application, so that you can use the icons in
|
||||
# the material Icons class.
|
||||
uses-material-design: true
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
assets:
|
||||
- assets/images/
|
||||
|
||||
|
|
Loading…
Reference in New Issue