Add job_details.dart

Deleted Comments ind pubspec.yaml
main
David 2023-06-13 01:03:02 +02:00
parent 094fa115c7
commit 4d04499dff
3 changed files with 610 additions and 37 deletions

View File

@ -1,6 +1,7 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'package:cloud_firestore/cloud_firestore.dart'; 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:cpd_ss23/services/global_methods.dart';
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -84,7 +85,15 @@ class _JobWidgetState extends State<JobWidget> {
elevation: 8, elevation: 8,
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: ListTile( child: ListTile(
onTap: () {}, onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => JobDetailsScreen(
uploadedBy: widget.uploadedBy,
jobID: widget.jobId,
)));
},
onLongPress: () { onLongPress: () {
_deleteDialog(); _deleteDialog();
}, },

View File

@ -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,
),
),
],
)),
],
),
),
),
),
],
),
),
),
);
}
}

View File

@ -1,39 +1,17 @@
name: cpd_ss23 name: cpd_ss23
description: A new Flutter project. 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 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 version: 1.0.0+1
environment: environment:
sdk: '>=3.0.0-378.0.dev <4.0.0' 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: dependencies:
flutter: flutter:
sdk: 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 cupertino_icons: ^1.0.2
cached_network_image: ^3.2.3 cached_network_image: ^3.2.3
image_picker: ^0.8.7+3 image_picker: ^0.8.7+3
@ -54,25 +32,12 @@ dev_dependencies:
flutter_test: flutter_test:
sdk: flutter 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 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: 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 uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets: assets:
- assets/images/ - assets/images/