diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4fee4b5e..0d6b0c95 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -6,12 +6,15 @@ additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> + - android:usesCleartextTraffic="true"> + android:icon="@mipmap/ic_launcher" + android:usesCleartextTraffic="true" + android:enableOnBackInvokedCallback="true"> + onDesignationChanged; + + const CustomAppBar({ + Key? key, + required this.curr_desig, + required this.headerTitle, + + required this.onDesignationChanged, + }) : super(key: key); + + @override + _CustomAppBarState createState() => _CustomAppBarState(); + + @override + Size get preferredSize => Size.fromHeight(kToolbarHeight); +} + +class _CustomAppBarState extends State { + late List designations; + late String current; + var service = locator(); + + @override + void initState() { + super.initState(); + designations = (service!.getFromDisk('designations') as List) + .map((dynamic item) => item.toString()) + .toList(); + + current = service!.getFromDisk( + 'Current_designation'); // Ensure designations is not null before accessing index 0 + } + + @override + Widget build(BuildContext context) { + return AppBar( + iconTheme: IconThemeData(color: Colors.white), + backgroundColor: kPrimaryColor, + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Padding( + padding: EdgeInsets.only(right: 20.0), // Add some right padding to ensure space for the dropdown + child: Text( + widget.headerTitle, // Example of a long title + overflow: TextOverflow.ellipsis, // Prevents overflow by adding ellipsis + style: TextStyle( + color: Colors.white, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + DropdownButtonHideUnderline( + child: DropdownButton( + padding: const EdgeInsets.all(15), + borderRadius: BorderRadius.circular(5), + value: current, + icon: Icon(Icons.arrow_drop_down, color: Colors.white), + iconSize: 24, + style: TextStyle(color: Colors.white, fontSize: 18), + dropdownColor: + kPrimaryColor, // Set the dropdown background color to orange + onChanged: (String? newValue) { + widget.onDesignationChanged(newValue!); + setState(() { + current = newValue!; + service!.saveToDisk('Current_designation', current); + }); + }, + items: designations.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text( + value, + style: TextStyle( + color: Colors.white), // Set the text color to white + ), + ); + }).toList(), + onTap: () { + // Find the index of the selected value + int index = designations.indexOf(current); + // Scroll the dropdown to the selected value + Scrollable.ensureVisible(context, + alignment: 0.5, duration: Duration(milliseconds: 300)); + }, + ), + ), + ], + ), + actions: [], + ); + } +} \ No newline at end of file diff --git a/lib/Components/bottom_navigation_bar.dart b/lib/Components/bottom_navigation_bar.dart new file mode 100644 index 00000000..f95ad3c3 --- /dev/null +++ b/lib/Components/bottom_navigation_bar.dart @@ -0,0 +1,148 @@ +import 'package:flutter/material.dart'; + +class MyBottomNavigationBar extends StatefulWidget { + @override + _MyBottomNavigationBarState createState() => _MyBottomNavigationBarState(); +} + +class _MyBottomNavigationBarState extends State { + bool _notificationsBool = false; + bool _announcementsBool = false; + bool _newsBool = false; + bool _homeBool = false; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 100.0, + child: Padding( + padding: EdgeInsets.only(bottom: 40), + child: Card( + color: Colors.deepOrangeAccent, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(17.0), + ), + child: Padding( + padding: const EdgeInsets.only( + left: 13.0, right: 10.0, top: 5.0, bottom: 5.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + GestureDetector( + onTap: () { + _notificationsBool = false; + _announcementsBool = false; + _newsBool = false; + _homeBool = true; + setState(() { + _notificationsBool = false; + _announcementsBool = false; + _newsBool = false; + _homeBool = true; + }); + Navigator.pushReplacementNamed(context, "/dashboard"); + + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Icon( + Icons.home_rounded, + color: Colors.white, + size: _homeBool ? 30.0 : 25.0, + ), + ], + ), + ), + GestureDetector( + onTap: () { + _newsBool = true; + _announcementsBool = false; + _notificationsBool = false; + _homeBool = false; + + setState(() { + _newsBool = true; + _announcementsBool = false; + _notificationsBool = false; + _homeBool = false; + }); + Navigator.pushReplacementNamed(context, "/news"); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Icon( + Icons.newspaper_rounded, + color: Colors.white, + size: _newsBool ? 30.0 : 25.0, + ), + ], + ), + ), + GestureDetector( + onTap: () { + _announcementsBool = false; + _newsBool = false; + _notificationsBool = true; + _homeBool = false; + + setState(() { + _announcementsBool = false; + _newsBool = false; + _notificationsBool = true; + _homeBool = false; + }); + Navigator.pushReplacementNamed(context, "/notification"); + }, + child: Padding( + padding: const EdgeInsets.only(right: 16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Icon( + Icons.notifications_active_rounded, + color: Colors.white, + size: _notificationsBool ? 30.0 : 25.0, + ), + ], + ), + ), + ), + GestureDetector( + onTap: () { + _announcementsBool = true; + _newsBool = false; + _notificationsBool = false; + _homeBool = false; + + setState(() { + _announcementsBool = true; + _newsBool = false; + _notificationsBool = false; + _homeBool = false; + }); + Navigator.pushReplacementNamed(context, "/announcement"); + }, + child: Padding( + padding: const EdgeInsets.only(right: 16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Icon( + Icons.campaign_rounded, + color: Colors.white, + size: _announcementsBool ? 30.0 : 25.0, + ), + ], + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/Components/side_drawer.dart b/lib/Components/side_drawer.dart index be08db0e..c6250f9a 100644 --- a/lib/Components/side_drawer.dart +++ b/lib/Components/side_drawer.dart @@ -121,6 +121,11 @@ class _SideDrawerState extends State { pageMover: '/programme_curriculum_home', isActive: true, ), + ModulesPadding( + line: 'Department Module', + pageMover: '/department_home_page', + isActive: true, + ), ModulesPadding( line: 'Gymkhana Module', pageMover: '/gymkhana_homepage'), diff --git a/lib/Components/side_drawer2.dart b/lib/Components/side_drawer2.dart new file mode 100644 index 00000000..0577b4aa --- /dev/null +++ b/lib/Components/side_drawer2.dart @@ -0,0 +1,291 @@ +import 'package:flutter/material.dart'; +import 'package:fusion/services/login_service.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; + +class SideDrawer extends StatefulWidget { + final String curr_desig; + + const SideDrawer({ + Key? key, + required this.curr_desig, + }) : super(key: key); + + @override + _SideDrawerState createState() => _SideDrawerState(); +} + +class _SideDrawerState extends State { + bool _loading = false; + int count = 0; + late String name; + late String depttype; + late String type; + @override + void initState() { + super.initState(); + var service = locator(); + print(service.profileData); + name = service.profileData.user!["first_name"] + + " " + + service.profileData.user!["last_name"]; + depttype = service.profileData.profile!['department']!['name']; + + type = service.profileData.profile!['user_type']; + print(depttype); + } + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Container( + margin: const EdgeInsets.only(right: 50.0), + height: MediaQuery.of(context).size.height, + color: Colors.white, + child: ListView( + shrinkWrap: true, + physics: ClampingScrollPhysics(), + children: [ + Column( + children: [ + Card( + elevation: 2.0, + margin: + EdgeInsets.symmetric(horizontal: 12.0, vertical: 30.0), + // shadowColor: Colors.black, + color: Colors.white, + + child: Column( + children: [ + Container( + margin: EdgeInsets.only(top: 0.0), + width: 270.0, + height: 120.0, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/profile_pic.png'), + fit: BoxFit.contain, + ), + ), + ), + SizedBox( + height: 10.0, + ), + Text( + name, //Display name of User + style: TextStyle( + fontSize: 20.0, + color: Colors.black, + fontWeight: FontWeight.bold), + ), + SizedBox( + height: 10.0, + ), + Text( + depttype + + " " + + widget.curr_desig, // Display Type of User + style: TextStyle( + fontSize: 17.0, + color: Colors.black, + fontWeight: FontWeight.bold), + ), + SizedBox( + height: 10.0, + ), + ], + ), + ), + ], + ), + ModulesCard(cardLine: 'DashBoard', pageMover: '/dashboard'), + + if ((type != "staff" || + widget.curr_desig == "acadmin" || + widget.curr_desig == "corelabcaretaker")) + ModulesCard( + cardLine: 'Academics Module', + pageMover: '/academic_home_page', + ), + + if ((type == "student" || widget.curr_desig == "acadmin")) + ModulesCard( + cardLine: 'Programme Curriculum', + pageMover: '/programme_curriculum_home', + ), + + if ((type == "student" || type == "faculty")) + ModulesCard( + cardLine: 'Department Module', + pageMover: '/department_home_page', + ), + + if ((type == "student") || + widget.curr_desig == "Dean_s" || + widget.curr_desig == "DeanPnD" || + widget.curr_desig == "dean_rspc" || + widget.curr_desig == "dean_s") + ModulesCard( + cardLine: 'Gymkhana Module', + pageMover: '/gymkhana_homepage', + ), + + if ((type == "student" || + widget.curr_desig == "mess_manager" || + widget.curr_desig == "mess_warden")) + ModulesCard( + cardLine: 'Central Mess Module', + pageMover: '/central_mess_home'), + + ModulesCard( + cardLine: 'Health Center Module', + pageMover: '/health_center', + ), + if ((type == "student")) ModulesCard(cardLine: 'Leave Module'), + + if ((type == "student")) + ModulesCard(cardLine: 'Purchase and Store'), + + if ((type == "student")) ModulesCard(cardLine: 'Human Resource'), + + if (type == "student" || + widget.curr_desig == "placement chairman" || + widget.curr_desig == "placement officer") + ModulesCard(cardLine: 'Placement Module'), + + ModulesCard( + cardLine: 'Visitors Hostel Module', + pageMover: '/visitor_hostel'), + + if (type != "student") + ModulesCard( + cardLine: 'File Tracking Module', pageMover: '/compose_file'), + + ModulesCard( + cardLine: 'Establishment Module', pageMover: '/establishment'), + + ModulesCard( + cardLine: 'Library Module', pageMover: '/library_homepage'), + + if (type == "student" || + widget.curr_desig == "spacsconvenor" || + widget.curr_desig == "spacsassistant") + ModulesCard(cardLine: 'Awards & Scholarship Module'), + + ModulesCard(cardLine: 'Complaint Module', pageMover: '/complaint'), + + ModulesCard(cardLine: 'Research Module'), + + ModulesCard(cardLine: 'Counselling Cell'), + + if ((type == "faculty" || widget.curr_desig == "acadadmin")) + ModulesCard( + cardLine: 'Examination Module', + pageMover: '/examination', + ), + + if ((widget.curr_desig == "Executive Engineer (Civil)" || + widget.curr_desig == "EE" || + widget.curr_desig == "Admin IWD" || + widget.curr_desig == "Electrical_AE" || + widget.curr_desig == "mess_manager" || + widget.curr_desig == "Electrical_JE" || + widget.curr_desig == "Civil_AE" || + widget.curr_desig == "Civil_JE" || + widget.curr_desig == "Director" || + widget.curr_desig == "dean_s" || + widget.curr_desig == "Dean_s" || + widget.curr_desig == "DeanPnD")) + ModulesCard(cardLine: 'IWD', pageMover: '/iwd/home_page'), + + ModulesCard( + cardLine: 'Courses Module', + pageMover: '/registered_courses', + ), + ModulesCard( + cardLine: 'HR Module', + pageMover: '/hr_homepage', + ), + + // ModulesCard( + // cardLine: 'Profile', + // icon: Icons.account_circle, + // pageMover: '/profile'), + + // ModulesCard(cardLine: 'Office Of Dean Students'), + // ModulesCard(cardLine: 'Office Of Dean Academics'), + // ModulesCard(cardLine: 'Director Office'), + // ModulesCard(cardLine: 'Office Of Purchase Officer'), + // ModulesCard(cardLine: 'Office Of Registrar'), + // ModulesCard(cardLine: 'Office Of P&D'), + // ModulesCard(cardLine: 'Office Of HOD (Branch)'), + // ModulesCard(cardLine: 'Finance & Accounts'), + // ModulesCard(cardLine: 'Meet Our Team'), + ModulesCard(cardLine: 'Log Out', icon: Icons.logout), + ], + ), + ), + ); + } + + String _getGymkhanaPage() { + // Determine the pageMover based on designation + print(widget.curr_desig); + if (widget.curr_desig == 'co-ordinator') { + return '/gymkhana_coordinator'; + } else if (widget.curr_desig == 'Counsellor') { + return '/gymkhana_counsellor'; + } else if (widget.curr_desig == 'Convenor') { + return '/gymkhana_convenor'; + } else if (widget.curr_desig == 'Dean Academic') { + return '/gymkhana_dean'; + } else + return '/gymkhana_homepage'; + } +// ignore: must_be_immutable +} + +class ModulesCard extends StatelessWidget { + final String? cardLine; + final String? pageMover; + IconData? icon; + ModulesCard({this.cardLine, this.icon, this.pageMover}); + @override + Widget build(BuildContext context) { + return GestureDetector( + //behaviour to translucent to get Tap even on blank or empty space within container + behavior: HitTestBehavior.translucent, + child: Card( + color: Colors.white, + margin: const EdgeInsets.all(10.0), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + cardLine!, + style: TextStyle(fontSize: 16.0, color: Colors.black), + ), + Icon( + icon, + color: Colors.deepOrangeAccent, + ), + ], + ), + ), + ), + onTap: () async { + var _prefs = await StorageService.getInstance(); + String token = _prefs!.userInDB?.token ?? ""; + if (cardLine == 'Log Out') { + LoginService auth = LoginService(); + auth.logout(); + Navigator.pushReplacementNamed(context, "/landing"); + } + if (pageMover != null) + Navigator.pushReplacementNamed(context, pageMover!, arguments: token); + }, + ); + } +} diff --git a/lib/DesignationProvider.dart b/lib/DesignationProvider.dart new file mode 100644 index 00000000..34031248 --- /dev/null +++ b/lib/DesignationProvider.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; + +class DesignationProvider extends ChangeNotifier { + late String _designation; + + String get designation => _designation; + + void updateDesignation(String newDesignation) { + _designation = newDesignation; + notifyListeners(); // Notify listeners about the change + } +} \ No newline at end of file diff --git a/lib/api.dart b/lib/api.dart index 73d1c6bc..24d6c50b 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -1,10 +1,12 @@ //Server and local links String klocalLink = "127.0.0.1:8000"; -String kserverLink = "172.27.16.214:8000"; +// String kserverLink = "172.27.16.214:8000"; +String kserverLink = "192.168.137.1:8000"; //Login Service -String kAuthUrl = "172.27.16.214:8000"; String kAuthLogin = "/api/auth/login/"; +// String kAuthUrl = "172.27.16.214:8000"; +String kAuthUrl = "192.168.137.1:8000"; // String kAuthLogin = "/accounts/login"; //Profile Service @@ -13,6 +15,11 @@ String kProfile = "/api/profile/"; //Academic Procedures String kAcademicProcedures = "/academic-procedures/api/stu/"; +//Department details +String kDepMain = "/dep/api/dep-main/"; +String kAllStudents = "/dep/api/all-students/"; +String kDepartmentAnnouncements = "/dep/api/announcements/"; + //Complaint String kComplaintService = "/complaint/api/studentcomplain"; String kComplaintNew = "/complaint/api/newcomplain"; @@ -21,6 +28,7 @@ String kComplaintRemove = "/complaint/api/removecomplain/"; //Dashboard String kDashboard = "/api/dashboard/"; +String kNotification = "/api/notification/"; String kNotificationRead = "/api/notification/read/"; //Gymkhana diff --git a/lib/main.dart b/lib/main.dart index 9ca81ff8..21353309 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,7 +9,10 @@ import 'package:fusion/screens/Library/Book_Search.dart'; import 'package:fusion/screens/Library/dues.dart'; import 'package:fusion/screens/Library/issued_items.dart'; import 'package:fusion/screens/Library/lib_home_screen.dart'; +import 'package:fusion/screens/LoginandDashboard/DashboardComponents/news.dart'; import 'package:fusion/screens/LoginandDashboard/dashboard.dart'; +import 'package:fusion/screens/LoginandDashboard/DashboardComponents/notify.dart'; +import 'package:fusion/screens/LoginandDashboard/DashboardComponents/announcement.dart'; import 'package:fusion/screens/LoginandDashboard/login_page.dart'; import 'package:fusion/screens/Academic/academic_home_page.dart'; import 'package:fusion/screens/Academic/Current_Semester/current_semester_home_page.dart'; @@ -35,6 +38,12 @@ import 'package:fusion/screens/Programme_Curriculum/Discipline/discipline.dart'; import 'package:fusion/screens/Programme_Curriculum/Programme/programme_home_page.dart'; import 'package:fusion/screens/Programme_Curriculum/Programme_Info/programme_info.dart'; import 'package:fusion/screens/Programme_Curriculum/programme_curriculum_home.dart'; +import 'package:fusion/screens/Department/department_homepage.dart'; +import 'package:fusion/screens/Department/Student_details/student_details.dart'; +import 'package:fusion/screens/Department/Alumni_details/alumni_details.dart'; +import 'package:fusion/screens/Department/Announcements/make_announcement.dart'; +import 'package:fusion/screens/Department/Announcements/browse_announcement.dart'; + import 'package:fusion/screens/landing_page.dart'; import 'package:fusion/screens/Healthcenter/healthcentermodule.dart'; import 'package:fusion/screens/Healthcenter/feedback.dart'; @@ -60,10 +69,12 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { MediaQueryData windowData = - MediaQueryData.fromWindow(WidgetsBinding.instance.window); + MediaQueryData.fromView(WidgetsBinding.instance.window); windowData = windowData.copyWith( - textScaleFactor: 1, + textScaler: TextScaler.linear(1), ); + var selectedProgramme; + Map selectedDepartmentData; return MediaQuery( data: windowData, child: MaterialApp( @@ -71,16 +82,19 @@ class MyApp extends StatelessWidget { title: 'Fusion', debugShowCheckedModeBanner: false, theme: ThemeData( - // primarySwatch: Colors.blueGrey, + // primarySwatch: Colors.blueGrey, // colorSchemeSeed: Color(0xFF2085D0), colorSchemeSeed: Color(0xFFF36C35), - fontFamily: 'Nunito', + fontFamily: 'Nunito', useMaterial3: true, ), initialRoute: '/landing', routes: { '/landing': (context) => LandingPage(), '/login_page': (context) => LoginPage(), + '/notification':(context)=>Notify(), + '/news':(context)=>News(), + '/announcement':(context)=>Announcement(), '/dashboard': (context) => Dashboard(), '/academic_home_page': (context) => AcademicHomePage( ModalRoute.of(context)!.settings.arguments.toString()), @@ -104,6 +118,12 @@ class MyApp extends StatelessWidget { ProgrammeInfo(), '/programme_curriculum_home/courses': (context) => Courses(), '/programme_curriculum_home/courses_info': (context) => CoursesInfo(), + '/department_home_page': (context) => DepartmentScreen( + ModalRoute.of(context)!.settings.arguments.toString()), + '/student_details': (context) => StudentDetails(), + '/alumni_details': (context) => AlumniDetails(), + '/browse_announcement': (context) => BrowseAnnouncement(), + '/make_announcement': (context) => MakeAnnouncement(), '/establishment': (context) => Establishment(), '/gymkhana_homepage': (context) => GymkhanaHomepage(), '/gymkhana_homepage/apply': (context) => Apply(), @@ -131,4 +151,4 @@ class MyApp extends StatelessWidget { ), ); } -} +} \ No newline at end of file diff --git a/lib/models/department.dart b/lib/models/department.dart new file mode 100644 index 00000000..66cdf4f2 --- /dev/null +++ b/lib/models/department.dart @@ -0,0 +1,199 @@ +class DepartmentData { + List students; + List alumni; + List faculty; + List announcements; + + DepartmentData({ + required this.students, + required this.alumni, + required this.faculty, + required this.announcements, + }); + + factory DepartmentData.fromJson(Map json) { + return DepartmentData( + students: List.from( + json['students'].map((student) => StudentData.fromJson(student))), + alumni: List.from( + json['alumni'].map((alumni) => AlumniData.fromJson(alumni))), + faculty: List.from( + json['faculty'].map((faculty) => FacultyData.fromJson(faculty))), + announcements: List.from(json['announcements'] + .map((announcement) => Announcement.fromJson(announcement))), + ); + } + + Map toJson() { + return { + 'students': students.map((student) => student.toJson()).toList(), + 'alumni': alumni.map((alumni) => alumni.toJson()).toList(), + 'faculty': faculty.map((faculty) => faculty.toJson()).toList(), + 'announcements': + announcements.map((announcement) => announcement.toJson()).toList(), + }; + } +} + +class StudentData { + var id; + var name; + var batchId; + var programme; + var batch; + var department; + + StudentData({ + this.id, + this.name, + this.batchId, + this.programme, + this.batch, + this.department, + }); + + factory StudentData.fromJson(Map json) { + return StudentData( + id: json['id'], + name: json['name'], + batchId: json['batchId'], + programme: json['programme'], + batch: json['batch'], + department: json['department'], + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'batchId': batchId, + 'programme': programme, + 'batch': batch, + 'department': department, + }; + } +} + +class AlumniData { + var id; + var name; + var batchId; + var programme; + var batch; + var department; + + AlumniData({ + this.id, + this.name, + this.batchId, + this.programme, + this.batch, + this.department, + }); + + factory AlumniData.fromJson(Map json) { + return AlumniData( + id: json['id'], + name: json['name'], + batchId: json['batchId'], + programme: json['programme'], + batch: json['batch'], + department: json['department'], + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'batchId': batchId, + 'programme': programme, + 'batch': batch, + 'department': department, + }; + } +} + +class FacultyData { + var id; + var facultyName; + var sex; + var dateOfBirth; + var address; + var phoneNumber; + + FacultyData({ + this.id, + this.facultyName, + this.sex, + this.dateOfBirth, + this.address, + this.phoneNumber, + }); + + factory FacultyData.fromJson(Map json) { + return FacultyData( + id: json['id'], + facultyName: json['facultyName'], + sex: json['sex'], + dateOfBirth: json['dateOfBirth'], + address: json['address'], + phoneNumber: json['phoneNumber'], + ); + } + + Map toJson() { + return { + 'id': id, + 'facultyName': facultyName, + 'sex': sex, + 'dateOfBirth': dateOfBirth, + 'address': address, + 'phoneNumber': phoneNumber, + }; + } +} + +class Announcement { + final String maker_id; + final DateTime ann_date; + final String message; + final String batch; + final String department; + final String programme; + final String? upload_announcement; + + Announcement({ + required this.maker_id, + required this.ann_date, + required this.message, + required this.batch, + required this.department, + required this.programme, + this.upload_announcement, + }); + factory Announcement.fromJson(Map json) { + return Announcement( + maker_id: json['maker_id'], + ann_date: json['ann_date'], + message: json['message'], + batch: json['batch'], + department: json['department'], + programme: json['programme'], + upload_announcement: json['upload_announcement'], + ); + } + + Map toJson() { + return { + 'maker_id': maker_id, + 'ann_date': ann_date, + 'message': message, + 'batch': batch, + 'department': department, + 'programme': programme, + 'upload_announcement': upload_announcement, + }; + } +} diff --git a/lib/screens/Department/Alumni_details/alumni_details.dart b/lib/screens/Department/Alumni_details/alumni_details.dart new file mode 100644 index 00000000..71dbe88c --- /dev/null +++ b/lib/screens/Department/Alumni_details/alumni_details.dart @@ -0,0 +1,193 @@ +import 'package:flutter/material.dart'; +import 'package:fusion/Components/appBar2.dart'; +import 'package:fusion/Components/side_drawer2.dart'; +import 'package:fusion/constants.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; + +class AlumniDetails extends StatefulWidget { + @override + _AlumniDetailsState createState() => _AlumniDetailsState(); +} + +class _AlumniDetailsState extends State + with SingleTickerProviderStateMixin { + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + + late TabController _tabController; + List departmentOptions = [ + 'CSE Department', + 'ECE Department', + 'ME Department', + 'SM Department' + ]; + String selectedDepartment = 'CSE Department'; + Color outlineColor = Colors.grey; + + List> alumniDetails = []; + + //API section + // Future fetchAlumniDetails() async { + // final response = await http.get( + // Uri.parse('https://your-django-api-endpoint/alumni-details'), + // ); + + // if (response.statusCode == 200) { + // final List data = json.decode(response.body); + + // setState(() { + // alumniDetails.clear(); + // for (final Map alumni in data) { + // alumniDetails.add({ + // 'ID': alumni['id'].toString(), + // 'Alumni Name': alumni['name'], + // 'Sex': alumni['sex'], + // 'Date of Birth': alumni['date_of_birth'], + // 'Address': alumni['address'], + // 'Phone Number': alumni['phone_no'], + // }); + // } + // }); + // } else { + // throw Exception('Failed to load alumni details'); + // } + // } + + @override + void initState() { + super.initState(); + _tabController = + TabController(length: departmentOptions.length, vsync: this); + _tabController.addListener(_handleTabSelection); + _tabController.index = 0; + } + + void _handleTabSelection() { + setState(() { + selectedDepartment = departmentOptions[_tabController.index]; + }); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + curr_desig: curr_desig, + headerTitle: "Department", + onDesignationChanged: (newValue) { + setState(() { + curr_desig = newValue; + }); + }, + ), + drawer: SideDrawer( + curr_desig: curr_desig, + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // SizedBox(height: 16), + Container( + color: kPrimaryColor, + child: TabBar( + controller: _tabController, + isScrollable: true, + indicatorColor: Colors.black, + labelColor: Colors.black, + unselectedLabelColor: Colors.white, + tabs: departmentOptions + .map((department) => Tab( + text: department, + )) + .toList(), + ), + ), + Expanded( + child: Container( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(0), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + ), + child: DataTable( + columns: [ + DataColumn( + label: Text('ID', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black)), + ), + DataColumn( + label: Text('Alumni Name', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black)), + ), + DataColumn( + label: Text('Sex', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black)), + ), + DataColumn( + label: Text('Date of Birth', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black)), + ), + DataColumn( + label: Text('Address', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black)), + ), + DataColumn( + label: Text('Phone Number', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black)), + ), + ], + rows: alumniDetails + .map( + (batch) => DataRow( + cells: [ + DataCell(Text(batch['ID']!)), + DataCell(Text(batch['Alumni Name']!)), + DataCell(Text(batch['Sex']!)), + DataCell(Text(batch['Date of Birth']!)), + DataCell(Text(batch['Address']!)), + DataCell(Text(batch['Phone Number']!)), + ], + ), + ) + .toList(), + ), + ), + ), + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/Department/Announcements/browse_announcement.dart b/lib/screens/Department/Announcements/browse_announcement.dart new file mode 100644 index 00000000..24e0db1e --- /dev/null +++ b/lib/screens/Department/Announcements/browse_announcement.dart @@ -0,0 +1,372 @@ +import 'dart:async'; +import 'package:fusion/Components/bottom_navigation_bar.dart'; +import 'package:fusion/constants.dart'; +import 'package:intl/intl.dart'; +import 'package:flutter/material.dart'; +import 'package:fusion/Components/appBar2.dart'; +import 'package:fusion/Components/side_drawer2.dart'; +import 'package:fusion/models/profile.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; +import 'package:fusion/services/department_service.dart'; +import 'package:fusion/screens/Department/Announcements/make_announcement.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +class BrowseAnnouncement extends StatefulWidget { + @override + _BrowseAnnouncementState createState() => _BrowseAnnouncementState(); +} + +enum AnnouncementSortingCriteria { date, announcementBy } + +class WebViewer extends StatefulWidget { + final String url; + const WebViewer({Key? key, required this.url}) : super(key: key); + @override + _WebViewerState createState() => _WebViewerState(); +} + +class _WebViewerState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Web Viewer'), + ), + body: WebView( + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), + ); + } +} +// String _getUsername(String makerId) { +// var profile = data!.profile; +// if (profile != null && profile['id'] == makerId) { +// var user = data!.user; +// if (user != null) { +// return user['username'] ?? ''; +// } +// } +// return ''; +// } + +class _BrowseAnnouncementState extends State + with SingleTickerProviderStateMixin { + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + + ProfileData? data; + late TabController _tabController; + List departmentOptions = ['All', 'CSE', 'ECE', 'ME', 'SM']; + final StreamController> _announcementsController = + StreamController>(); + AnnouncementSortingCriteria? _sortingCriteria; + bool _isAscending = true; + + @override + void initState() { + super.initState(); + _tabController = TabController( + length: departmentOptions.length, + vsync: this, + ); + _tabController.addListener(_handleTabSelection); + _tabController.index = 0; // Initialize the index + var service = locator(); + data = service.profileData; + _loadAnnouncements(); + } + + void _handleTabSelection() { + setState(() { + _loadAnnouncements(); + }); + } + + void _loadAnnouncements() async { + int selectedIndex = _tabController.index; + String department = departmentOptions[selectedIndex]; + List announcements = + await DepartmentService().getDepartmentsAnnouncements(department); + _sortAnnouncements(announcements); + } + + void _sortAnnouncements(List announcements) { + if (_sortingCriteria == AnnouncementSortingCriteria.date) { + announcements.sort((a, b) => + DateTime.parse(a.ann_date).compareTo(DateTime.parse(b.ann_date))); + } else if (_sortingCriteria == AnnouncementSortingCriteria.announcementBy) { + announcements.sort((a, b) => a.maker_id.compareTo(b.maker_id)); + } + if (!_isAscending) { + announcements = announcements.reversed.toList(); + } + _announcementsController.add(announcements); + } + + void _toggleSortOrder() { + setState(() { + _isAscending = !_isAscending; + }); + _loadAnnouncements(); + } + + void _setSortingCriteria(AnnouncementSortingCriteria? criteria) { + setState(() { + _sortingCriteria = criteria; + }); + _loadAnnouncements(); + } + + @override + void dispose() { + _announcementsController.close(); + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + String? userRole = data?.profile?['user_type']; + return Scaffold( + appBar: CustomAppBar( + curr_desig: curr_desig, + headerTitle: "Department", + onDesignationChanged: (newValue) { + setState(() { + curr_desig = newValue; + }); + }, + ), + drawer: SideDrawer( + curr_desig: curr_desig, + ), + bottomNavigationBar: MyBottomNavigationBar(), + body: Column( + children: [ + Container( + color: kPrimaryColor, + child: TabBar( + controller: _tabController, + isScrollable: true, + indicatorColor: Colors.black, + labelColor: Colors.black, + unselectedLabelColor: Colors.white, + tabs: departmentOptions + .map((department) => Tab( + text: department, + )) + .toList(), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (userRole == 'faculty') + ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MakeAnnouncement(), + ), + ); + }, + child: Icon(Icons.add, size: 20), + ), + SizedBox(width: 8), + ElevatedButton( + onPressed: () { + _loadAnnouncements(); + }, + child: Text( + 'Announcements', + style: TextStyle(fontSize: 18), // Set font size here + ), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: DropdownButton( + hint: Text('Sort by'), + value: _sortingCriteria, + onChanged: _setSortingCriteria, + items: [ + DropdownMenuItem( + child: Text('Sort by Date'), + value: AnnouncementSortingCriteria.date, + ), + DropdownMenuItem( + child: Text('Sort by Announcement By'), + value: AnnouncementSortingCriteria.announcementBy, + ), + ], + ), + ), + ), + IconButton( + icon: Icon( + _isAscending ? Icons.arrow_upward : Icons.arrow_downward), + onPressed: _toggleSortOrder, + ), + ], + ), + Expanded( + child: Container( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(0), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: StreamBuilder>( + stream: _announcementsController.stream, + builder: (context, snapshot) { + if (snapshot.hasData) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + ), + child: DataTable( + columns: [ + DataColumn( + label: Text( + 'Announcement Date', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black), + ), + ), + DataColumn( + label: Text( + 'Announcement By', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black), + ), + ), + DataColumn( + label: Text( + 'Programme', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black), + ), + ), + DataColumn( + label: Text( + 'Batch', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black), + ), + ), + DataColumn( + label: Text( + 'Message', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black), + ), + ), + DataColumn( + label: Text( + 'File', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black), + ), + ), + ], + rows: snapshot.data! + .map( + (announcement) => DataRow( + cells: [ + DataCell(Text( + DateFormat('MMM. dd, yyyy') + .format(DateTime.parse( + announcement.ann_date)))), + DataCell(Text(announcement.maker_id)), + // DataCell(Text(_getUsername(announcement + // .maker_id))), // Updated line + DataCell( + Text(announcement.programme)), + DataCell(Text(announcement.batch)), + DataCell(Container( + width: 250, + child: Text( + announcement.message, + softWrap: true, + ), + )), + DataCell( + announcement.upload_announcement != + null + ? TextButton( + onPressed: () { + String? fileUrl = + announcement + .upload_announcement; + if (fileUrl != null && + fileUrl.isNotEmpty) { + Navigator.push( + context, + MaterialPageRoute( + builder: + (context) => + WebViewer( + url: fileUrl, + ), + ), + ); + } + }, + child: Text( + 'Open File', + style: TextStyle( + color: Colors.blue, + decoration: + TextDecoration + .underline, + ), + ), + ) + : SizedBox(), + ), + ], + ), + ) + .toList(), + ), + ), + ); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return Center(child: CircularProgressIndicator()); + } + }, + ), + ), + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/Department/Announcements/make_announcement.dart b/lib/screens/Department/Announcements/make_announcement.dart new file mode 100644 index 00000000..37975b55 --- /dev/null +++ b/lib/screens/Department/Announcements/make_announcement.dart @@ -0,0 +1,359 @@ +import 'dart:async'; +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:fusion/Components/appBar2.dart'; +import 'package:fusion/Components/side_drawer2.dart'; +import 'package:fusion/Components/bottom_navigation_bar.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:fusion/services/department_service.dart'; +import 'package:fusion/models/profile.dart'; +import 'package:fusion/services/profile_service.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; +import 'package:http/http.dart'; + +class MakeAnnouncement extends StatefulWidget { + @override + _MakeAnnouncementState createState() => _MakeAnnouncementState(); +} + +class _MakeAnnouncementState extends State { + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + + late ProfileData? data; + late ProfileService profileService; + List> announcements = []; + final _formKey = GlobalKey(); + List programmeTypes = [null, 'B.Tech', 'M.Tech', 'Ph.D']; + List departmentTypes = [null, 'ALL', 'CSE', 'ECE', 'ME', 'SM']; + List batches = [null, 'ALL', 'Year-1', 'Year-2', 'Year-3', 'Year-4']; + + late String ann_date; + String? selectedProgrammeType; + String? selectedBatch; + String? selectedDepartmentType; + String? programmeWarning; + String? departmentWarning; + String? selectedFilePath = null; + TextEditingController announcementDetailsController = TextEditingController(); + + @override + void initState() { + super.initState(); + var service = locator(); + profileService = ProfileService(); + data = service.profileData; + announcementDetailsController = TextEditingController(); + getData(); + } + + getData() async { + try { + Response response = await profileService.getProfile(); + setState(() { + data = ProfileData.fromJson(jsonDecode(response.body)); + }); + } catch (e) { + print(e); + } + } + + @override + void dispose() { + announcementDetailsController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + curr_desig: curr_desig, + headerTitle: "Department", + onDesignationChanged: (newValue) { + setState(() { + curr_desig = newValue; + }); + }, + ), + drawer: SideDrawer( + curr_desig: curr_desig, + ), + bottomNavigationBar: MyBottomNavigationBar(), + body: SingleChildScrollView( + child: Column( + children: [ + Container( + margin: EdgeInsets.all(5.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(1.0), + ), + child: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: () { + Navigator.pop( + context, + MaterialPageRoute( + builder: (context) => MakeAnnouncement(), + ), + ); + }, + child: Icon(Icons.announcement, size: 20), + ), + SizedBox(width: 8), + ElevatedButton( + onPressed: () { + setState(() { + programmeWarning = null; + departmentWarning = null; + }); + }, + child: Text( + 'Make Announcement', + style: TextStyle(fontSize: 18), + ), + ), + ], + ), + ), + ), + Container( + margin: EdgeInsets.all(20.0), + padding: EdgeInsets.all(20.0), + decoration: BoxDecoration( + color: Color.fromRGBO(255, 234, 228, 1), + borderRadius: BorderRadius.circular(10.0), + ), + child: Form( + key: _formKey, + child: Column( + children: [ + buildDropdown('Programme Type', programmeTypes, + selectedProgrammeType, 'Select Programme', (newValue) { + setState(() { + selectedProgrammeType = newValue; + programmeWarning = null; + }); + }), + if (programmeWarning != null) + Padding( + padding: const EdgeInsets.only(left: 0.0), + child: Text( + programmeWarning!, + style: TextStyle(color: Colors.red), + ), + ), + SizedBox(height: 16), + buildDropdown( + 'Batch', batches, selectedBatch, 'Select Batch', + (newValue) { + setState(() { + selectedBatch = newValue; + }); + }), + SizedBox(height: 16), + buildDropdown( + 'Department Type', + departmentTypes, + selectedDepartmentType, + 'Select Department', (newValue) { + setState(() { + selectedDepartmentType = newValue; + departmentWarning = null; + }); + }), + if (departmentWarning != null) + Padding( + padding: const EdgeInsets.only(left: 0.0), + child: Text( + departmentWarning!, + style: TextStyle(color: Colors.red), + ), + ), + SizedBox(height: 16), + TextFormField( + controller: announcementDetailsController, + decoration: InputDecoration( + labelText: 'Announcement Details:*', + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'This field is required'; + } + return null; + }, + ), + SizedBox(height: 16), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.only(left: 8), + child: Text( + 'Attach Files(pdf, jpeg, jpg, png):', + style: TextStyle(fontSize: 16), + ), + ), + SizedBox(height: 8), + IntrinsicWidth( + child: Row( + children: [ + ElevatedButton( + onPressed: () { + _showFilePickerDialog(context); + }, + child: Text('Choose File'), + ), + SizedBox(width: 8), + Text(selectedFilePath ?? 'No file chosen'), + ], + ), + ), + ], + ), + SizedBox(height: 16), + ElevatedButton( + onPressed: () { + submitForm(); + }, + child: Text('Publish'), + ), + ], + ), + ), + ), + ], + ), + ), + resizeToAvoidBottomInset: true, + ); + } + + Future _showFilePickerDialog(BuildContext context) async { + try { + FilePickerResult? result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: ['pdf', 'jpg', 'jpeg', 'png'], + ); + + if (result != null) { + setState(() { + selectedFilePath = result.files.single.path!; + }); + } else { + print('User canceled file picking'); + } + } catch (e) { + print("Error picking file: $e"); + } + } + + Future submitForm() async { + setState(() { + programmeWarning = + selectedProgrammeType == null ? 'Please select programme' : null; + departmentWarning = + selectedDepartmentType == null ? 'Please select department' : null; + }); + if (_formKey.currentState!.validate()) { + Map announcementData = { + 'maker_id': data!.profile!['id'], + 'ann_date': DateTime.now().toIso8601String(), + 'programme': selectedProgrammeType, + 'batch': selectedBatch, + 'department': selectedDepartmentType, + 'message': announcementDetailsController.text, + 'upload_announcement': selectedFilePath, + }; + Future success = + DepartmentService().createAnnouncement(announcementData); + if (await success) { + _showSuccessSnackbar(); + } else { + _showFailureSnackbar(); + } + } + } + + void _showSuccessSnackbar() { + setState(() { + _formKey.currentState!.reset(); + selectedBatch = null; + selectedProgrammeType = null; + selectedDepartmentType = null; + selectedFilePath = null; + announcementDetailsController.clear(); + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Announcement Created Successfully', + style: TextStyle(color: Colors.white), + ), + duration: Duration(seconds: 5), + backgroundColor: Colors.green, + ), + ); + } + + void _showFailureSnackbar() { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Failed to create announcement. Please try again later.', + style: TextStyle(color: Colors.white), + ), + duration: Duration(seconds: 5), + backgroundColor: Colors.red, + ), + ); + } + + Widget buildDropdown(String label, List items, String? selectedValue, + String placeholder, Function(String?) onChanged) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + label + ':', + ), + if (label == 'Programme Type' || label == 'Department Type') + Text( + '*', + style: TextStyle(color: Colors.red), + ), + ], + ), + SizedBox(width: 8), + InputDecorator( + decoration: InputDecoration( + border: OutlineInputBorder(), + contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 3), + fillColor: Color.fromARGB(255, 245, 242, 242), + filled: true, + ), + child: DropdownButtonHideUnderline( + child: DropdownButton( + value: selectedValue, + onChanged: (newValue) { + onChanged(newValue); + }, + items: items.map((item) { + return DropdownMenuItem( + value: item, + child: Text(item ?? placeholder), + ); + }).toList(), + ), + ), + ), + ], + ); + } +} diff --git a/lib/screens/Department/Department_Info/facilities.dart b/lib/screens/Department/Department_Info/facilities.dart new file mode 100644 index 00000000..945b1010 --- /dev/null +++ b/lib/screens/Department/Department_Info/facilities.dart @@ -0,0 +1,177 @@ +import 'package:flutter/material.dart'; +import 'package:fusion/models/profile.dart'; +import 'package:fusion/Components/side_drawer2.dart'; +import 'package:fusion/screens/Department/Department_Info/updateinfo.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; + +class FacilitiesPage extends StatefulWidget { + final String selectedDepartment; + FacilitiesPage({required this.selectedDepartment}); + @override + _FacilitiesPageState createState() => _FacilitiesPageState(); +} + +class _FacilitiesPageState extends State + with SingleTickerProviderStateMixin { + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + + ProfileData? data; + late TabController _tabController; + + void initState() { + super.initState(); + var service = locator(); + data = service.profileData; + + _tabController = TabController( + length: 2, + vsync: this, + ); + _tabController.addListener(_handleTabSelection); + _tabController.index = 0; + } + + void _handleTabSelection() {} + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + String centralLibraryInfo; + String labInfraInfo; + + switch (widget.selectedDepartment) { + case 'CSE Department': + centralLibraryInfo = + "Institute library has e-resources through INDEST, Science Direct, IEEE, ACM, Springger Link, Nature and ASME. The Institute also has access to various online research journals & articles like following resources SIAm, AMS, ACS, Kluwer, APS, Palgrave, INFORMS, Rev.of Scientific Instruments, Appl.Physics Letters and the search engine Scopus. Total number of books in the Institute library by the year 2009-10 are approximately 6742.\n\nHigh Performance Computing Labortory : Specification of Parallel Cluster (for Central Computing Facility)- JS22 Blade No.3, 16GB(2*8GB) DDR2 533 Mhz DiMMs, IBM 146GB SAS 10K SFF HDD, IBM blade center JS22 4-core 4.0 Ghz Processor and WiFi Campus etc."; + labInfraInfo = + "1. Advanced Manufacturing Laboratory : This Laboratory contains Rapid Prototyping Machine, CNC Controlled Abrasive Waterjet Machine, CNC Milling Center, CNC Turning Center, Dynamometer, Electro Chemical Machining System, Injection Moulding Machine etc.\n\n2. Biometric Laboratory : This Laboratory contains S Series, H Series, W Series cameras and p6 p520(Tower Model), p6 p520:8203 Model servers Made by IBM etc.\n\n3. Digital Signal Processing and Image Processing Laboratory : This Laboratory contains DSP Starter SPARTAN-3 kit (DSK), TMS 320C6713 DSK with CCS (Code Composer Studio), Image Daughter Kit with CCD Cameras, Bloom with DSP, Matrox Imaging Library, Matrox Morphis, Frame Graber Card, Color CCD Camera for online Processing etc.\n\n4. Infrared Imaging Laboratory : This Laboratory contains Radiometeric calibration, Extender rings, NDT Base Module, Central computing unit with TFT display, Software Modules for Lockin, Transient-and Pulse Measurement, Module Pulse- and Transient- Thermography, Source for Vibro- Thermography etc.\n\n5. Materials Research Laboratory : This Laboratory contains three important instruments for material characterization which are X-Ray Diffractometer (XRD), Scanning Electron Microscope (SEM) and Atomic Force Microscope (AFM) including SPM, MFM etc."; + break; + case 'ECE Department': + centralLibraryInfo = "ECE Department Central Library Info"; + labInfraInfo = "ECE Department Lab Infrastructure Info"; + break; + case 'ME Department': + centralLibraryInfo = "ME Department Central Library Info"; + labInfraInfo = "ME Department Lab Infrastructure Info"; + break; + case 'SM Department': + centralLibraryInfo = "SM Department Central Library Info"; + labInfraInfo = "SM Department Lab Infrastructure Info"; + break; + default: + centralLibraryInfo = "No information available"; + labInfraInfo = "No information available"; + } + + bool isHODForSelectedDepartment = + _isHODForDepartment(curr_desig, widget.selectedDepartment); + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.black, + title: Text( + 'Facilities', + style: TextStyle(fontSize: 25, color: Colors.white), + ), + actions: [ + Padding( + padding: EdgeInsets.all(8.0), + child: Icon(Icons.search), + ), + Padding( + padding: EdgeInsets.all(8.0), + child: Icon(Icons.notifications), + ), + Padding( + padding: EdgeInsets.all(8.0), + child: Icon(Icons.more_vert), + ), + ], + bottom: TabBar( + isScrollable: true, + indicatorColor: Colors.white, + indicatorWeight: 6.0, + controller: _tabController, + tabs: [ + Tab( + child: Container( + child: Text( + 'Central Library', + ), + ), + ), + Tab( + child: Container( + child: Text( + 'Lab Infrastructure', + ), + ), + ), + ], + ), + ), + drawer: SideDrawer( + curr_desig: curr_desig, + ), + body: TabBarView( + controller: _tabController, + children: [ + ListView( + padding: const EdgeInsets.all(16.0), + children: [ + SizedBox(height: 16), + Text( + centralLibraryInfo, + style: TextStyle(fontSize: 16), + ), + ], + ), + ListView( + padding: const EdgeInsets.all(16.0), + children: [ + SizedBox(height: 16), + Text( + labInfraInfo, + style: TextStyle(fontSize: 16), + ), + ], + ), + ], + ), + floatingActionButton: isHODForSelectedDepartment + ? FloatingActionButton.extended( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => UpdateInfoPage(), + ), + ); + }, + label: Text('Update Department Info'), + ) + : null, + ); + } +} + +bool _isHODForDepartment(String currDesig, String selectedDepartment) { + switch (selectedDepartment) { + case 'CSE Department': + return currDesig == 'HOD (CSE)'; + case 'ECE Department': + return currDesig == 'HOD (ECE)'; + case 'ME Department': + return currDesig == 'HOD (ME)'; + case 'SM Department': + return currDesig == 'HOD (SM)'; + default: + return false; + } +} diff --git a/lib/screens/Department/Department_Info/updateinfo.dart b/lib/screens/Department/Department_Info/updateinfo.dart new file mode 100644 index 00000000..f9d05601 --- /dev/null +++ b/lib/screens/Department/Department_Info/updateinfo.dart @@ -0,0 +1,196 @@ +import 'package:flutter/material.dart'; +import 'package:fusion/Components/side_drawer2.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; + +class UpdateInfoPage extends StatefulWidget { + @override + _UpdateInfoPageState createState() => _UpdateInfoPageState(); +} + +class _UpdateInfoPageState extends State { + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + TextEditingController _emailController = TextEditingController(); + TextEditingController _contactNumberController = TextEditingController(); + TextEditingController _facilitiesController = TextEditingController(); + TextEditingController _linkController = TextEditingController(); + late FocusNode _facilitiesFocusNode; + late FocusNode _linkFocusNode; + + late Color facilitiesBorderColor; + late Color linkBorderColor; + + @override + void initState() { + super.initState(); + _facilitiesFocusNode = FocusNode(); + _linkFocusNode = FocusNode(); + facilitiesBorderColor = Colors.grey; + linkBorderColor = Colors.grey; + + _facilitiesFocusNode.addListener(() { + setState(() { + facilitiesBorderColor = _facilitiesFocusNode.hasFocus + ? Theme.of(context).colorScheme.primary + : Colors.grey; + }); + }); + + _linkFocusNode.addListener(() { + setState(() { + linkBorderColor = _linkFocusNode.hasFocus + ? Theme.of(context).colorScheme.primary + : Colors.grey; + }); + }); + } + + @override + void dispose() { + _facilitiesFocusNode.dispose(); + _linkFocusNode.dispose(); + super.dispose(); + } + + void _onFacilitiesFocusChange(bool hasFocus) { + setState(() { + facilitiesBorderColor = + hasFocus ? Theme.of(context).colorScheme.primary : Colors.grey; + }); + } + + void _onLinkFocusChange(bool hasFocus) { + setState(() { + linkBorderColor = + hasFocus ? Theme.of(context).colorScheme.primary : Colors.grey; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.black, + title: Text( + 'Update Information', + style: TextStyle(fontSize: 20, color: Colors.white), + ), + actions: [ + Padding( + padding: EdgeInsets.all(8.0), + child: Icon(Icons.search), + ), + Padding( + padding: EdgeInsets.all(8.0), + child: Icon(Icons.notifications), + ), + Padding( + padding: EdgeInsets.all(8.0), + child: Icon(Icons.more_vert), + ), + ], + ), + drawer: SideDrawer( + curr_desig: curr_desig, + ), + body: ListView( + padding: const EdgeInsets.all(16.0), + children: [ + TextField( + controller: _emailController, + decoration: InputDecoration( + labelText: 'Email', + hintText: 'Enter email', + ), + ), + SizedBox(height: 16.0), + TextField( + controller: _contactNumberController, + decoration: InputDecoration( + labelText: 'Contact Number', + hintText: 'Enter contact number', + ), + ), + SizedBox(height: 24.0), + _buildTextFieldWithFocusNode( + labelText: 'Facilities', + hintText: 'Enter facilities offered by the department', + controller: _facilitiesController, + focusNode: _facilitiesFocusNode, + borderColor: facilitiesBorderColor, + onFocusChange: _onFacilitiesFocusChange, + ), + SizedBox(height: 24.0), + _buildTextFieldWithFocusNode( + labelText: 'Labs', + hintText: 'Enter lab information of the department', + controller: _linkController, + focusNode: _linkFocusNode, + borderColor: linkBorderColor, + onFocusChange: _onLinkFocusChange, + ), + SizedBox(height: 24.0), + ElevatedButton( + onPressed: () {}, + child: Text('Update Information'), + ), + ], + ), + ); + } + + Widget _buildTextFieldWithFocusNode({ + required String labelText, + required String hintText, + required TextEditingController controller, + required FocusNode focusNode, + required Color borderColor, + required ValueChanged onFocusChange, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + labelText, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18.0, + ), + ), + SizedBox(height: 8.0), + Container( + padding: EdgeInsets.only(left: 10.0, right: 10.0, bottom: 40.0), + decoration: BoxDecoration( + border: Border.all( + color: borderColor, + ), + borderRadius: BorderRadius.circular(8.0), + ), + child: TextField( + controller: controller, + focusNode: focusNode, + maxLines: null, + decoration: InputDecoration( + border: InputBorder.none, + hintText: hintText, + contentPadding: EdgeInsets.symmetric(vertical: 16.0), + ), + onChanged: (value) { + onFocusChange(true); + }, + onTap: () { + onFocusChange(true); + }, + onEditingComplete: () { + onFocusChange(false); + }, + onSubmitted: (value) { + onFocusChange(false); + }, + ), + ), + ], + ); + } +} diff --git a/lib/screens/Department/Faculty_details/faculty_details.dart b/lib/screens/Department/Faculty_details/faculty_details.dart new file mode 100644 index 00000000..b9e896a9 --- /dev/null +++ b/lib/screens/Department/Faculty_details/faculty_details.dart @@ -0,0 +1,246 @@ +import 'package:flutter/material.dart'; +import 'package:fusion/Components/appBar2.dart'; +import 'package:fusion/Components/side_drawer2.dart'; +import 'package:fusion/constants.dart'; +import 'package:fusion/models/profile.dart'; +import 'package:fusion/services/department_service.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; + +class FacultyDetailsScreen extends StatefulWidget { + final String selectedDepartment; + FacultyDetailsScreen({required this.selectedDepartment}); + @override + _FacultyDetailsState createState() => _FacultyDetailsState(); +} + +class _FacultyDetailsState extends State + with SingleTickerProviderStateMixin { + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + + ProfileData? data; + late TabController _tabController; + List departmentOptions = [ + 'CSE Department', + 'ECE Department', + 'ME Department', + 'SM Department' + ]; + List facultyDetails = []; + late String updatedDepartment; + bool isLoading = false; + + @override + void initState() { + super.initState(); + _tabController = + TabController(length: departmentOptions.length, vsync: this); + _tabController.addListener(_handleTabSelection); + _tabController.index = 0; + var service = locator(); + data = service.profileData; + updatedDepartment = widget.selectedDepartment; + _handleTabSelection(); + } + + void _handleTabSelection() { + final newDepartment = departmentOptions[_tabController.index].split(' ')[0]; + if (updatedDepartment != newDepartment) { + setState(() { + isLoading = true; + }); + updatedDepartment = newDepartment; + DepartmentService().getFacultyDetails(updatedDepartment).then((data) { + setState(() { + facultyDetails = + data?.map((json) => FacultyDetails.fromJson(json)).toList() ?? []; + isLoading = false; + }); + }); + } + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + curr_desig: curr_desig, + headerTitle: "Department", + onDesignationChanged: (newValue) { + setState(() { + curr_desig = newValue; + }); + }, + ), + drawer: SideDrawer( + curr_desig: curr_desig, + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + color: kPrimaryColor, + child: TabBar( + controller: _tabController, + isScrollable: true, + indicatorColor: Colors.black, + labelColor: Colors.black, + unselectedLabelColor: Colors.white, + tabs: departmentOptions + .map((department) => Tab( + text: department, + )) + .toList(), + ), + ), + Expanded( + child: Container( + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: FutureBuilder>>( + future: + DepartmentService().getFacultyDetails(updatedDepartment), + builder: ((context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Center(child: CircularProgressIndicator()); + } else if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}')); + } else { + facultyDetails = snapshot.data + ?.map((json) => FacultyDetails.fromJson(json)) + .toList() ?? + []; + if (facultyDetails.isEmpty) { + return Padding( + padding: EdgeInsets.all(20), + child: Text( + 'No data available', + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ); + } else { + return DataTable( + columns: [ + DataColumn( + label: Text( + 'ID', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + DataColumn( + label: Text( + 'Title', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + DataColumn( + label: Text( + 'Sex', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + DataColumn( + label: Text( + 'Date of Birth', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + DataColumn( + label: Text( + 'Address', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + DataColumn( + label: Text( + 'Phone Number', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + DataColumn( + label: Text( + 'User', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + DataColumn( + label: Text( + 'Department', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + ], + rows: facultyDetails + .map( + (faculty) => DataRow( + cells: [ + DataCell(Text(faculty.id)), + DataCell(Text(faculty.title)), + DataCell(Text(faculty.sex)), + DataCell(Text(faculty.dateOfBirth)), + DataCell(Text(faculty.address)), + DataCell( + Text(faculty.phoneNumber.toString())), + DataCell(Text(faculty.user.toString())), + DataCell(Text(faculty.department.toString())), + ], + ), + ) + .toList(), + ); + } + } + }), + ), + ), + ))), + ], + ), + ); + } +} diff --git a/lib/screens/Department/Student_details/batch_details.dart b/lib/screens/Department/Student_details/batch_details.dart new file mode 100644 index 00000000..25a0df7b --- /dev/null +++ b/lib/screens/Department/Student_details/batch_details.dart @@ -0,0 +1,334 @@ +import 'package:flutter/material.dart'; +import 'package:fusion/models/profile.dart'; +import 'package:fusion/Components/side_drawer2.dart'; +import 'package:fusion/screens/Department/Student_details/filter.dart'; +import 'package:fusion/services/department_service.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; + +class BatchDetails extends StatefulWidget { + final String selectedProgramme; + final Map selectedDepartmentData; + BatchDetails( + {required this.selectedProgramme, required this.selectedDepartmentData}); + + @override + _BatchDetailsState createState() => _BatchDetailsState(); +} + +enum StudentSortingCriteria { cpi, currentSemesterNo } + +class _BatchDetailsState extends State + with SingleTickerProviderStateMixin { + late int bid; + ProfileData? data; + late TabController _tabController; + List> batchDetails = []; + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + StudentSortingCriteria? _sortingCriteria; + bool _isAscending = true; + + @override + void initState() { + super.initState(); + var service = locator(); + data = service.profileData; + bid = + generateBid(widget.selectedProgramme, widget.selectedDepartmentData, 1); + _tabController = TabController( + length: _calculateTabCount(), + vsync: this, + ); + _tabController.addListener(_handleTabSelection); + _tabController.index = 0; + } + + int _calculateTabCount() { + int tabCount = 0; + String programme = widget.selectedProgramme; + if (programme == 'PhD') { + tabCount = 1; + } else if (programme == 'M.Tech') { + tabCount = 2; + } else if (programme == 'B.Tech') { + tabCount = 4; + } + return tabCount; + } + + void _handleTabSelection() { + int year = _tabController.index + 1; + int newBid = generateBid( + widget.selectedProgramme, widget.selectedDepartmentData, year); + if (bid != newBid) { + bid = newBid; + DepartmentService().getStudents(bid).then((data) { + setState(() { + batchDetails = data ?? []; + }); + }); + } + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + void _sortStudents(List> students) { + if (_sortingCriteria == StudentSortingCriteria.cpi) { + students.sort((a, b) => a['cpi'].compareTo(b['cpi'])); + } else if (_sortingCriteria == StudentSortingCriteria.currentSemesterNo) { + students.sort( + (a, b) => a['curr_semester_no'].compareTo(b['curr_semester_no'])); + } + if (!_isAscending) { + students = students.reversed.toList(); + } + setState(() { + batchDetails = students; + }); + } + + void _toggleSortOrder() { + setState(() { + _isAscending = !_isAscending; + }); + _sortStudents(batchDetails); + } + + void _setSortingCriteria(StudentSortingCriteria? criteria) { + setState(() { + _sortingCriteria = criteria; + }); + _sortStudents(batchDetails); + } + + void applyFilters(Map> selectedFilters) {} + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.black, + title: Text( + 'Students', + style: TextStyle(fontSize: 25, color: Colors.white), + ), + actions: [ + Padding( + padding: EdgeInsets.all(8.0), + child: Icon(Icons.search), + ), + Padding( + padding: EdgeInsets.all(8.0), + child: Icon(Icons.notifications), + ), + Padding( + padding: EdgeInsets.all(8.0), + child: Icon(Icons.more_vert), + ), + ], + bottom: TabBar( + isScrollable: true, + indicatorColor: Colors.white, + indicatorWeight: 6.0, + controller: _tabController, + tabs: _buildTabs(), + ), + ), + drawer: SideDrawer( + curr_desig: curr_desig, + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + flex: 10, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: DropdownButton( + hint: Text('Sort by'), + value: _sortingCriteria, + onChanged: _setSortingCriteria, + items: [ + DropdownMenuItem( + child: Text('Sort by CPI'), + value: StudentSortingCriteria.cpi, + ), + DropdownMenuItem( + child: Text('Sort by Semester No'), + value: StudentSortingCriteria.currentSemesterNo, + ), + ], + ), + ), + ), + IconButton( + icon: Icon( + _isAscending ? Icons.arrow_upward : Icons.arrow_downward), + onPressed: _toggleSortOrder, + ), + Padding( + padding: const EdgeInsets.only(right: 5.0), + child: IconButton( + icon: Icon(Icons.filter_list), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + FilterScreen(onApplyFilters: applyFilters)), + ); + }, + ), + ), + ], + ), + Expanded( + child: Container( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(0), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: FutureBuilder>>( + future: DepartmentService().getStudents(bid), + builder: ((context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return Center(child: CircularProgressIndicator()); + } else if (snapshot.hasError) { + return Center( + child: Text('Error: ${snapshot.error}')); + } else { + batchDetails = snapshot.data ?? []; + return batchDetails.isNotEmpty + ? DataTable( + columns: batchDetails.first.entries + .map( + (entry) => DataColumn( + label: Text( + entry.key.toUpperCase(), + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + ) + .toList(), + rows: batchDetails + .map( + (batch) => DataRow( + cells: batch.entries + .map( + (entry) => DataCell( + Text( + entry.value?.toString() ?? + ''), + ), + ) + .toList(), + ), + ) + .toList(), + ) + : Padding( + padding: EdgeInsets.all(20), + child: Text( + 'No data available', + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ); + } + }), + ), + ), + ), + ), + ), + ) + ], + ), + ); + } + + List _buildTabs() { + List tabs = []; + String programme = widget.selectedProgramme; + if (programme == 'PhD') { + tabs.add(Tab( + child: Text( + '${widget.selectedProgramme} ', + ), + )); + } else if (programme == 'M.Tech') { + tabs.add(Tab( + child: Text( + 'M.Tech 1st Year', + ), + )); + tabs.add(Tab( + child: Text( + 'M.Tech 2nd Year', + ), + )); + } else if (programme == 'B.Tech') { + tabs.add(Tab( + child: Text( + 'B.Tech 1st Year', + ), + )); + tabs.add(Tab( + child: Text( + 'B.Tech 2nd Year', + ), + )); + tabs.add(Tab( + child: Text( + 'B.Tech 3rd Year', + ), + )); + tabs.add(Tab( + child: Text( + 'B.Tech 4th Year', + ), + )); + } + return tabs; + } + + int generateBid( + String programme, Map departmentData, int year) { + String departmentCode = + widget.selectedDepartmentData['departmentCode'] ?? ''; + String bid = departmentCode; + Map batchLengths = { + 'PhD': 6, + 'M.Tech': 4, + 'B.Tech': 1, + }; + if (programme == 'PhD') { + bid += '1'.padRight(batchLengths[programme]!, '1'); + } else if (programme == 'M.Tech') { + bid += '1'.padRight(batchLengths[programme]! + (year == 2 ? 1 : 0), '1'); + } else if (programme == 'B.Tech') { + if (year == 1) bid = bid; + if (year == 2) bid += '1'.padRight(batchLengths[programme]!, '1'); + if (year == 3) bid += '1'.padRight(batchLengths[programme]! + 1, '1'); + if (year == 4) bid += '1'.padRight(batchLengths[programme]! + 2, '1'); + } + return int.parse(bid); + } +} diff --git a/lib/screens/Department/Student_details/filter.dart b/lib/screens/Department/Student_details/filter.dart new file mode 100644 index 00000000..04d794b5 --- /dev/null +++ b/lib/screens/Department/Student_details/filter.dart @@ -0,0 +1,105 @@ +import 'package:flutter/material.dart'; + +class FilterScreen extends StatefulWidget { + final Function(Map> selectedFilters) onApplyFilters; + FilterScreen({required this.onApplyFilters}); + + @override + _FilterScreenState createState() => _FilterScreenState(); +} + +class _FilterScreenState extends State { + final Map> categoryFilters = { + 'CPI': { + 'Below 5.0': false, + '5.0 - 6.0': false, + '6.0 - 7.0': false, + '7.0 - 8.0': false, + '8.0 - 9.0': false, + '9.0 - 10.0': false, + }, + 'Hostel': { + 'Hall 1': false, + 'Hall 2': false, + 'Hall 3': false, + 'Hall 4': false, + }, + 'Category': { + 'GEN': false, + 'OBC': false, + 'SC': false, + 'ST': false, + }, + }; + + String selectedCategory = 'CPI'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Filters'), + actions: [ + Padding( + padding: EdgeInsets.only(right: 10.0), + child: TextButton( + onPressed: () { + setState(() { + categoryFilters.forEach((key, value) { + value.updateAll((key, value) => false); + }); + }); + }, + child: Text( + 'Clear Filters', + style: TextStyle(color: Colors.black, fontSize: 16), + ), + ), + ) + ], + ), + body: Row( + children: [ + NavigationRail( + selectedIndex: + categoryFilters.keys.toList().indexOf(selectedCategory), + onDestinationSelected: (int index) { + setState(() { + selectedCategory = categoryFilters.keys.toList()[index]; + }); + }, + labelType: NavigationRailLabelType.all, + destinations: categoryFilters.keys + .map((category) => NavigationRailDestination( + icon: Icon(Icons.filter_list), + selectedIcon: Icon(Icons.filter_list), + label: Text(category), + )) + .toList(), + ), + Expanded( + child: ListView( + children: categoryFilters[selectedCategory]!.entries.map((entry) { + return CheckboxListTile( + title: Text(entry.key, style: TextStyle(color: Colors.black)), + value: entry.value, + onChanged: (bool? value) { + setState(() { + categoryFilters[selectedCategory]![entry.key] = value!; + }); + }, + ); + }).toList(), + )), + ], + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + widget.onApplyFilters(categoryFilters); + Navigator.pop(context); + }, + child: Icon(Icons.check), + ), + ); + } +} diff --git a/lib/screens/Department/Student_details/student_details.dart b/lib/screens/Department/Student_details/student_details.dart new file mode 100644 index 00000000..3d6eaefb --- /dev/null +++ b/lib/screens/Department/Student_details/student_details.dart @@ -0,0 +1,295 @@ +import 'package:flutter/material.dart'; +import 'package:fusion/Components/appBar2.dart'; +import 'package:fusion/Components/bottom_navigation_bar.dart'; +import 'package:fusion/Components/side_drawer2.dart'; +import 'package:fusion/constants.dart'; +import 'package:fusion/models/profile.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; +import 'package:fusion/screens/Department/Student_details/batch_details.dart'; + +class StudentDetails extends StatefulWidget { + @override + _StudentDetailsState createState() => _StudentDetailsState(); +} + +class _StudentDetailsState extends State { + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + + ProfileData? data; + late String programme; + late String selectedDepartment; + + @override + void initState() { + super.initState(); + var service = locator(); + data = service.profileData; + if (data != null && + data!.profile != null && + data!.profile!['department'] != null) { + selectedDepartment = + data!.profile!['department']!['name'] + ' Department'; + } else { + selectedDepartment = 'CSE Department'; + } + } + + List departmentOptions = [ + 'CSE Department', + 'ECE Department', + 'ME Department', + 'SM Department' + ]; + Map departmentCodes = { + 'CSE Department': '1', + 'ECE Department': '2', + 'ME Department': '3', + 'SM Department': '4', + }; + + @override + Widget build(BuildContext context) { + Color outlineColor = Colors.grey; + return Scaffold( + appBar: CustomAppBar( + curr_desig: curr_desig, + headerTitle: "Department", + onDesignationChanged: (newValue) { + setState(() { + curr_desig = newValue; + }); + }, + ), + drawer: SideDrawer( + curr_desig: curr_desig, + ), + bottomNavigationBar: MyBottomNavigationBar(), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Card( + elevation: 2.0, + shadowColor: Colors.black, + color: Color.fromARGB(255, 255, 237, 232), + child: Padding( + padding: EdgeInsets.only( + top: 10.0, bottom: 12.0, left: 24, right: 24), + child: Column( + children: [ + Container( + margin: EdgeInsets.only(top: 22.0), + width: 180.0, // Increased width + height: 160.0, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/unknown.jpg'), + fit: BoxFit.fill, + ), + ), + ), + SizedBox( + height: 10.0, + ), + Text( + data!.user!['first_name'] + + ' ' + + data!.user!['last_name'], + style: TextStyle(fontSize: 20.0, color: Colors.black), + ), + SizedBox( + height: 8.0, + ), + RichText( + text: TextSpan( + text: data!.profile!['department']!['name'], + style: + TextStyle(fontSize: 15.0, color: Colors.black), + children: [ + TextSpan(text: ' '), + TextSpan( + text: curr_desig, + style: TextStyle( + fontSize: 15.0, color: Colors.black), + ), + ], + ), + ), + SizedBox( + height: 10.0, + ), + ], + ), + ), + ), + Container( + margin: EdgeInsets.only(top: 15.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + color: kPrimaryColor, + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 2), + ), + ], + ), + child: Tab( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + color: Colors.deepOrangeAccent, + ), + child: Align( + alignment: Alignment.center, + child: Text( + 'Students', + style: TextStyle( + fontSize: 24, + color: Colors.white, + ), + ), + ), + ), + ), + ), + SizedBox(height: 32), + ElevatedButton( + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5.0), + ), + side: BorderSide(color: kPrimaryColor), + foregroundColor: kPrimaryColor, + backgroundColor: Colors.white, + minimumSize: Size(550, 50), + ), + onPressed: () async { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => BatchDetails( + selectedProgramme: 'PhD', + selectedDepartmentData: { + 'department': selectedDepartment, + 'departmentCode': + departmentCodes[selectedDepartment] ?? '', + }, + ), + ), + ); + }, + child: Text( + 'PhD Students', + style: TextStyle(fontSize: 18), + ), + ), + SizedBox(height: 10), + ElevatedButton( + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5.0), + ), + side: BorderSide(color: kPrimaryColor), + foregroundColor: kPrimaryColor, + backgroundColor: Colors.white, + minimumSize: Size(550, 50), + ), + onPressed: () async { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => BatchDetails( + selectedProgramme: 'M.Tech', + selectedDepartmentData: { + 'department': selectedDepartment, + 'departmentCode': + departmentCodes[selectedDepartment] ?? '', + }, + ), + ), + ); + }, + child: Text( + 'M.Tech Students', + style: TextStyle(fontSize: 18), + ), + ), + SizedBox(height: 10), + ElevatedButton( + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5.0), + ), + side: BorderSide(color: kPrimaryColor), + foregroundColor: kPrimaryColor, + backgroundColor: Colors.white, + minimumSize: Size(550, 50), + ), + onPressed: () async { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => BatchDetails( + selectedProgramme: 'B.Tech', + selectedDepartmentData: { + 'department': selectedDepartment, + 'departmentCode': + departmentCodes[selectedDepartment] ?? '', + }, + ), + ), + ); + }, + child: Text( + 'B.Tech Students', + style: TextStyle(fontSize: 18), + ), + ), + SizedBox(height: 32), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox(width: 18), + Container( + padding: EdgeInsets.symmetric(horizontal: 12.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + border: Border.all(color: outlineColor, width: 2.0), + ), + child: DropdownButton( + value: departmentOptions.contains(selectedDepartment) + ? selectedDepartment + : '----------', + items: departmentOptions.map((String department) { + return DropdownMenuItem( + value: department, + child: Text(department), + ); + }).toList() + ..add(DropdownMenuItem( + value: '----------', child: Text('----------'))), + onChanged: (String? newValue) { + if (newValue != null && newValue != '----------') { + setState(() { + selectedDepartment = newValue; + }); + } + }, + underline: SizedBox(), + ), + ), + ], + ), + ], + ), + ), + )); + } +} diff --git a/lib/screens/Department/department_homepage.dart b/lib/screens/Department/department_homepage.dart new file mode 100644 index 00000000..e09524c0 --- /dev/null +++ b/lib/screens/Department/department_homepage.dart @@ -0,0 +1,357 @@ +// ignore_for_file: must_be_immutable +import 'dart:async'; +import 'dart:convert'; +import 'package:http/http.dart'; +import 'package:flutter/material.dart'; +import 'package:fusion/constants.dart'; +import 'package:fusion/models/profile.dart'; +import 'package:fusion/Components/appBar2.dart'; +import 'package:fusion/Components/side_drawer2.dart'; +import 'package:fusion/screens/Department/Alumni_details/alumni_details.dart'; +import 'package:fusion/screens/Department/Faculty_details/faculty_details.dart'; +import 'package:fusion/screens/Department/Announcements/browse_announcement.dart'; +import 'package:fusion/screens/Department/Student_details/student_details.dart'; +import 'package:fusion/screens/Department/Department_Info/facilities.dart'; +import 'package:fusion/services/profile_service.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; +import 'package:fusion/Components/bottom_navigation_bar.dart'; + +class DepartmentScreen extends StatefulWidget { + String? token; + DepartmentScreen(this.token); + @override + _DepartmentScreenState createState() => _DepartmentScreenState(); +} + +class _DepartmentScreenState extends State { + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + + late StreamController _profileController; + late ProfileService profileService; + late ProfileData? data; + bool _loading = true; + late var fetchedDepartment; + late String selectedDepartment; + + @override + void initState() { + super.initState(); + _profileController = StreamController(); + profileService = ProfileService(); + var service = locator(); + data = service.profileData; + getData(); + + if (data != null && + data!.profile != null && + data!.profile!['department'] != null) { + selectedDepartment = + data!.profile!['department']!['name'] + ' Department'; + } else { + selectedDepartment = 'CSE Department'; + } + } + + getData() async { + try { + Response response = await profileService.getProfile(); + setState(() { + data = ProfileData.fromJson(jsonDecode(response.body)); + // print(data!.user!); + // print(data!.profile!); + _loading = false; + }); + } catch (e) { + print(e); + } + } + + loadData() async { + getData().then((res) { + _profileController.add(res); + }); + } + + List departmentOptions = [ + 'CSE Department', + 'ECE Department', + 'ME Department', + 'SM Department' + ]; + + @override + Widget build(BuildContext context) { + Color customColor = kPrimaryColor; + Color outlineColor = Colors.grey; + + return Scaffold( + appBar: CustomAppBar( + curr_desig: curr_desig, + headerTitle: "Department", + onDesignationChanged: (newValue) { + setState(() { + curr_desig = newValue; + }); + }, + ), + drawer: SideDrawer( + curr_desig: curr_desig, + ), + bottomNavigationBar: MyBottomNavigationBar(), + body: _loading == true + ? Center(child: CircularProgressIndicator()) + : SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Card( + elevation: 2.0, + shadowColor: Colors.black, + color: Color.fromARGB(255, 255, 237, 232), + child: Padding( + padding: EdgeInsets.only( + top: 10.0, bottom: 12.0, left: 24, right: 24), + child: Column( + children: [ + Container( + margin: EdgeInsets.only(top: 22.0), + width: 180.0, // Increased width + height: 160.0, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/unknown.jpg'), + fit: BoxFit.fill, + ), + ), + ), + SizedBox( + height: 10.0, + ), + Text( + data!.user!['first_name'] + + ' ' + + data!.user!['last_name'], + style: TextStyle( + fontSize: 20.0, color: Colors.black), + ), + SizedBox( + height: 8.0, + ), + RichText( + text: TextSpan( + text: data!.profile!['department']!['name'], + style: TextStyle( + fontSize: 15.0, color: Colors.black), + children: [ + TextSpan(text: ' '), + TextSpan( + text: curr_desig, + style: TextStyle( + fontSize: 15.0, color: Colors.black), + ), + ], + ), + ), + SizedBox( + height: 10.0, + ), + ], + ), + ), + ), + SizedBox(height: 15), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: const EdgeInsets.all(32), + decoration: BoxDecoration( + color: Color.fromRGBO(255, 234, 228, 1), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + SizedBox( + width: 250, + height: 60, + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => FacilitiesPage( + selectedDepartment: + selectedDepartment), + ), + ); + }, + child: Text('Facilities', + style: TextStyle(fontSize: 20)), + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: customColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(22), + ), + ), + ), + ), + SizedBox(height: 14), + SizedBox( + width: 250, + height: 60, + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + StudentDetails(), + ), + ); + }, + child: Text('Student details', + style: TextStyle(fontSize: 20)), + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: customColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(22), + ), + ), + ), + ), + SizedBox(height: 14), + SizedBox( + width: 250, + height: 60, + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + FacultyDetailsScreen( + selectedDepartment: data! + .profile![ + 'department']!['name']), + ), + ); + }, + child: Text('Faculty details', + style: TextStyle(fontSize: 20)), + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: customColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(22), + ), + ), + ), + ), + SizedBox(height: 14), + SizedBox( + width: 250, + height: 60, + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AlumniDetails(), + ), + ); + }, + child: Text('Alumni details', + style: TextStyle(fontSize: 20)), + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: customColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(22), + ), + ), + ), + ), + SizedBox(height: 14), + SizedBox( + width: 250, + height: 60, + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + BrowseAnnouncement()), + ); + }, + child: Text('Announcements', + style: TextStyle(fontSize: 20)), + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: customColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(22), + ), + ), + ), + ), + ], + ), + ), + ], + ), + ), + SizedBox(height: 32), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox(width: 18), + Container( + padding: EdgeInsets.symmetric(horizontal: 12.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + border: Border.all(color: outlineColor, width: 2.0), + ), + child: DropdownButton( + value: + departmentOptions.contains(selectedDepartment) + ? selectedDepartment + : '----------', + items: departmentOptions.map((String department) { + return DropdownMenuItem( + value: department, + child: Text(department), + ); + }).toList() + ..add(DropdownMenuItem( + value: '----------', + child: Text('----------'))), + onChanged: (String? newValue) { + if (newValue != null && + newValue != '----------') { + setState(() { + selectedDepartment = newValue; + }); + } + }, + underline: SizedBox(), + ), + ), + ], + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/LoginandDashboard/DashboardComponents/announcement.dart b/lib/screens/LoginandDashboard/DashboardComponents/announcement.dart new file mode 100644 index 00000000..c0db276f --- /dev/null +++ b/lib/screens/LoginandDashboard/DashboardComponents/announcement.dart @@ -0,0 +1,200 @@ +import 'dart:async'; +import 'dart:convert'; +import 'package:fusion/models/profile.dart'; +import 'package:fusion/services/profile_service.dart'; +import 'package:flutter/material.dart'; +import 'package:fusion/Components/appBar2.dart'; +import 'package:fusion/Components/side_drawer2.dart'; +import 'package:fusion/models/dashboard.dart'; +import 'package:fusion/screens/LoginandDashboard/DashboardComponents/cardItems.dart'; +import 'package:fusion/services/dashboard_service.dart'; +import 'package:http/http.dart'; +import 'package:fusion/Components/bottom_navigation_bar.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; + +class Announcement extends StatefulWidget { + static String tag = 'home-page'; + @override + _AnnouncementState createState() => _AnnouncementState(); +} + +class _AnnouncementState extends State { + bool _notificationsBool = false; + bool _newsBool = false; + bool _announcementsBool = true; + bool _homeBool = false; + + bool _loading = true; + late String name; + late String studentType; + // Stream Controller for API + late StreamController _dashboardController; + late DashboardService dashboardService; + late DashboardData data; + late StreamController _profileController; + late ProfileService profileService; + late ProfileData data2; + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + @override + void initState() { + super.initState(); + _dashboardController = StreamController(); + dashboardService = DashboardService(); + _profileController = StreamController(); + profileService = ProfileService(); + getData(); + } + + getData() async { + try { + print("gfsgsgd"); + Response response = await dashboardService.getDashboard(); + print("1"); + Response response2 = await profileService.getProfile(); + print("2"); + print(response); + print(response2); + + setState(() { + data = DashboardData.fromJson(jsonDecode(response.body)); + data2 = ProfileData.fromJson(jsonDecode(response2.body)); + _loading = false; + }); + name = data2.user!['first_name'] + ' ' + data2.user!['last_name']; + studentType = data2.profile!['department']!['name'] + + ' ' + + data2.profile!['user_type']; + } catch (e) { + print(e); + } + } + + loadData() async { + getData().then((res) { + _dashboardController.add(res); + _profileController.add(res); + }); + } + + final GlobalKey scaffoldKey = new GlobalKey(); + showSnack() { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('New Content Loaded'), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + curr_desig: curr_desig, + headerTitle: "Announcement", + + onDesignationChanged: (newValue) { + setState(() { + curr_desig = newValue; + }); + }, + ), + bottomNavigationBar: MyBottomNavigationBar(), + drawer: SideDrawer(curr_desig: curr_desig), + body: _loading == true + ? Center(child: CircularProgressIndicator()) + : StreamBuilder( + stream: _dashboardController.stream, + builder: (context, AsyncSnapshot snapshot) { + return Stack(children: [ + Positioned( + left: 0, + child: Column( + children: [ + Card( + elevation: 0, + margin: EdgeInsets.symmetric( + horizontal: 10.0, vertical: 10.0), + color: Colors.transparent, + child: Padding( + padding: const EdgeInsets.only( + top: 10.0, + bottom: 10.0, + left: 13.0, + right: 10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + GestureDetector( + onTap: () { + _notificationsBool = true; + _announcementsBool = false; + _newsBool = false; + setState(() { + _notificationsBool = true; + _announcementsBool = false; + _newsBool = false; + }); + Navigator.pushReplacementNamed( + context, "/notification"); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + GestureDetector( + onTap: () { + // Only handle navigation when the icon is clicked + _notificationsBool = false; + _announcementsBool = true; + _newsBool = false; + setState(() { + _notificationsBool = false; + _announcementsBool = true; + _newsBool = false; + }); + Navigator.pushReplacementNamed( + context, "/landing"); + }, + child: Icon( + Icons.navigate_before_rounded, + color: Colors.black, + size: 25.0, + ), + ), + SizedBox(width: 20.0), + Text( + 'Announcement', + style: TextStyle( + fontSize: 22.0, + color: Colors.black, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(width: 170.0), + ], + ), + ), + ], + ), + ), + ), + + + ], + ), + ), + ]); + }, + ), + ); + } + + @override + void dispose() { + _dashboardController.close(); + super.dispose(); + } +} \ No newline at end of file diff --git a/lib/screens/LoginandDashboard/DashboardComponents/cardItems.dart b/lib/screens/LoginandDashboard/DashboardComponents/cardItems.dart index fffcde98..63afcdd9 100644 --- a/lib/screens/LoginandDashboard/DashboardComponents/cardItems.dart +++ b/lib/screens/LoginandDashboard/DashboardComponents/cardItems.dart @@ -1,36 +1,34 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:fusion/models/notification.dart' as notif; import 'package:fusion/services/dashboard_service.dart'; class NotificationCard extends StatelessWidget { final List? notifications; - const NotificationCard({Key? key, required this.notifications}) - : super(key: key); + const NotificationCard({Key? key, required this.notifications}) : super(key: key); @override Widget build(BuildContext context) { return Card( elevation: 2.0, - margin: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0), + margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0), shadowColor: Colors.black, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: getCards(), + child: SingleChildScrollView( // Added to allow scrolling + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: getCards(), + ), ), ); } - getCards() { - List cards = []; - for (int i = 0; i < notifications!.length; i++) { - cards.add(InfoCard( - notification: notifications![i], - )); - } - return cards; + List getCards() { + // Transforming the notifications into InfoCard widgets + return notifications!.map((notif.Notification notification) { + return InfoCard( + notification: notification, + ); + }).toList(); } } @@ -38,19 +36,20 @@ class NewsCard extends StatelessWidget { @override Widget build(BuildContext context) { return Card( - elevation: 2.0, - margin: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0), + elevation: 0, + margin: EdgeInsets.symmetric( + horizontal: 10.0, vertical: 10.0), shadowColor: Colors.black, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Card( elevation: 3.0, - margin: EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0), + margin: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0), shadowColor: Colors.black, - child: Center( + child: const Center( child: Padding( - padding: const EdgeInsets.all(18.0), + padding: EdgeInsets.all(18.0), child: Text('Work in progress'), ), ), @@ -64,9 +63,10 @@ class NewsCard extends StatelessWidget { class InfoCard extends StatefulWidget { final notif.Notification notification; - InfoCard({ + const InfoCard({ + Key? key, required this.notification, - }); + }) : super(key: key); @override _InfoCardState createState() => _InfoCardState(); @@ -77,46 +77,38 @@ class _InfoCardState extends State { Widget build(BuildContext context) { return Card( elevation: 3.0, - margin: EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0), + margin: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0), shadowColor: Colors.black, child: Column( children: [ - SizedBox( - height: 10.0, - ), + const SizedBox(height: 10.0), Text( widget.notification.data!["module"], textAlign: TextAlign.left, - style: TextStyle( + style: const TextStyle( fontSize: 20.0, color: Colors.deepOrangeAccent, fontWeight: FontWeight.bold, ), ), - SizedBox( - height: 10.0, - ), + const SizedBox(height: 10.0), Padding( padding: const EdgeInsets.all(8.0), child: Text( widget.notification.verb!, - style: TextStyle(fontSize: 15.0, color: Colors.black), + style: const TextStyle(fontSize: 15.0, color: Colors.black), ), ), - SizedBox( - height: 10.0, - ), + const SizedBox(height: 10.0), ElevatedButton( - child: widget.notification.unread! - ? Text('Mark As Read') - : Text('Mark As Unread'), + child: Text(widget.notification.unread! ? 'Mark As Read' : 'Mark As Unread'), onPressed: () { // Respond to button press DashboardService service = DashboardService(); setState(() { try { service.markRead(widget.notification.id!.toString()); - }catch(e){ + } catch (e) { print(e); } }); @@ -124,10 +116,8 @@ class _InfoCardState extends State { style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith( (Set states) { - if (states.contains(MaterialState.pressed)) - return Colors.deepOrange; - return Colors - .deepOrangeAccent; // Use the component's default. + if (states.contains(MaterialState.pressed)) return Colors.deepOrange; + return Colors.deepOrangeAccent; // Default Color }, ), ), diff --git a/lib/screens/LoginandDashboard/DashboardComponents/news.dart b/lib/screens/LoginandDashboard/DashboardComponents/news.dart new file mode 100644 index 00000000..268ae36a --- /dev/null +++ b/lib/screens/LoginandDashboard/DashboardComponents/news.dart @@ -0,0 +1,201 @@ +import 'dart:async'; +import 'dart:convert'; +import 'package:fusion/models/profile.dart'; +import 'package:fusion/services/profile_service.dart'; +import 'package:flutter/material.dart'; +import 'package:fusion/Components/appBar2.dart'; +import 'package:fusion/Components/side_drawer2.dart'; +import 'package:fusion/models/dashboard.dart'; +import 'package:fusion/screens/LoginandDashboard/DashboardComponents/cardItems.dart'; +import 'package:fusion/services/dashboard_service.dart'; +import 'package:http/http.dart'; +import 'package:fusion/Components/bottom_navigation_bar.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; + +class News extends StatefulWidget { + static String tag = 'home-page'; + @override + _NewsState createState() => _NewsState(); +} + +class _NewsState extends State { + bool _notificationsBool = false; + bool _newsBool = true; + bool _announcementsBool = false; + bool _homeBool = false; + + bool _loading = true; + late String name; + late String studentType; + // Stream Controller for API + late StreamController _dashboardController; + late DashboardService dashboardService; + late DashboardData data; + late StreamController _profileController; + late ProfileService profileService; + late ProfileData data2; + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + + @override + void initState() { + super.initState(); + _dashboardController = StreamController(); + dashboardService = DashboardService(); + _profileController = StreamController(); + profileService = ProfileService(); + getData(); + } + + getData() async { + try { + print("gfsgsgd"); + Response response = await dashboardService.getDashboard(); + print("1"); + Response response2 = await profileService.getProfile(); + print("2"); + print(response); + print(response2); + + setState(() { + data = DashboardData.fromJson(jsonDecode(response.body)); + data2 = ProfileData.fromJson(jsonDecode(response2.body)); + _loading = false; + }); + name = data2.user!['first_name'] + ' ' + data2.user!['last_name']; + studentType = data2.profile!['department']!['name'] + + ' ' + + data2.profile!['user_type']; + } catch (e) { + print(e); + } + } + + loadData() async { + getData().then((res) { + _dashboardController.add(res); + _profileController.add(res); + }); + } + + final GlobalKey scaffoldKey = new GlobalKey(); + showSnack() { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('New Content Loaded'), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + curr_desig: curr_desig, + headerTitle: "News", + + onDesignationChanged: (newValue) { + setState(() { + curr_desig = newValue; + }); + }, + ), + drawer: SideDrawer(curr_desig: curr_desig), + bottomNavigationBar: MyBottomNavigationBar(), + body: _loading == true + ? Center(child: CircularProgressIndicator()) + : StreamBuilder( + stream: _dashboardController.stream, + builder: (context, AsyncSnapshot snapshot) { + return Stack(children: [ + Positioned( + left: 0, + child: Column( + children: [ + Card( + elevation: 0, + margin: EdgeInsets.symmetric( + horizontal: 10.0, vertical: 10.0), + color: Colors.transparent, + child: Padding( + padding: const EdgeInsets.only( + top: 10.0, + bottom: 10.0, + left: 13.0, + right: 10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + GestureDetector( + onTap: () { + _notificationsBool = true; + _announcementsBool = false; + _newsBool = false; + setState(() { + _notificationsBool = true; + _announcementsBool = false; + _newsBool = false; + }); + Navigator.pushReplacementNamed( + context, "/notification"); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + GestureDetector( + onTap: () { + // Only handle navigation when the icon is clicked + _notificationsBool = true; + _announcementsBool = false; + _newsBool = false; + setState(() { + _notificationsBool = true; + _announcementsBool = false; + _newsBool = false; + }); + Navigator.pushReplacementNamed( + context, "/landing"); + }, + child: Icon( + Icons.navigate_before_rounded, + color: Colors.black, + size: 25.0, + ), + ), + SizedBox(width: 20.0), + Text( + 'News', + style: TextStyle( + fontSize: 22.0, + color: Colors.black, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(width: 170.0), + ], + ), + ), + ], + ), + ), + ), + + + ], + ), + ), + ]); + }, + ), + ); + } + + @override + void dispose() { + _dashboardController.close(); + super.dispose(); + } +} \ No newline at end of file diff --git a/lib/screens/LoginandDashboard/DashboardComponents/notify.dart b/lib/screens/LoginandDashboard/DashboardComponents/notify.dart new file mode 100644 index 00000000..198820b5 --- /dev/null +++ b/lib/screens/LoginandDashboard/DashboardComponents/notify.dart @@ -0,0 +1,152 @@ +import 'dart:async'; +import 'dart:convert'; +import 'package:fusion/models/profile.dart'; +import 'package:fusion/services/profile_service.dart'; +import 'package:flutter/material.dart'; +import 'package:fusion/Components/appBar2.dart'; +import 'package:fusion/Components/side_drawer2.dart'; +import 'package:fusion/models/dashboard.dart'; +import 'package:fusion/screens/LoginandDashboard/DashboardComponents/cardItems.dart'; +import 'package:fusion/services/dashboard_service.dart'; +import 'package:http/http.dart'; +import 'package:fusion/Components/bottom_navigation_bar.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; +import 'package:fusion/models/notification.dart' as notif; +import 'package:intl/intl.dart'; + +class Notify extends StatefulWidget { + static String tag = 'home-page'; + @override + _NotifyState createState() => _NotifyState(); +} + +class _NotifyState extends State { + List _notifications = []; + bool _loading = true; + late String name; + late String studentType; + + // Stream Controller for API + late StreamController _dashboardController; + late DashboardService dashboardService; + late DashboardData data; + late StreamController _profileController; + late ProfileService profileService; + late ProfileData data2; + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + @override + void initState() { + super.initState(); + _dashboardController = StreamController(); + dashboardService = DashboardService(); + _profileController = StreamController(); + profileService = ProfileService(); + getData(); + } + + getData() async { + try { + print("gfsgsgd"); + Response response = await dashboardService.getNotification(); + print("1"); + Response response2 = await profileService.getProfile(); + print("2"); + print(response); + print(response2); + + setState(() { + data = DashboardData.fromJson(jsonDecode(response.body)); + _notifications = notif.Notification.fromListJson(jsonDecode(response.body)['notifications']); + data2 = ProfileData.fromJson(jsonDecode(response2.body)); + _loading = false; + }); + name = data2.user!['first_name'] + ' ' + data2.user!['last_name']; + studentType = data2.profile!['department']!['name'] + + ' ' + + data2.profile!['user_type']; + } catch (e) { + print(e); + } + } + + loadData() async { + getData().then((res) { + _dashboardController.add(res); + _profileController.add(res); + }); + } + + final GlobalKey scaffoldKey = new GlobalKey(); + showSnack() { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('New Content Loaded'), + ), + ); + } + + @override +Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + curr_desig: curr_desig, + headerTitle: "Notifications", + + onDesignationChanged: (newValue) { + setState(() { + curr_desig = newValue; + }); + }, + ), // This is default app bar used in all modules + drawer: SideDrawer(curr_desig: curr_desig), + bottomNavigationBar: + MyBottomNavigationBar(), // This is sideDrawer used in all modules + body: _loading + ? Center(child: CircularProgressIndicator()) + : ListView.builder( + itemCount: _notifications.length, + padding: EdgeInsets.all(8.0), // Add padding around the list for better spacing + itemBuilder: (context, index) { + final notification = _notifications[index]; + final formattedDate = notification.timestamp != null + ? DateFormat('yyyy-MM-dd – kk:mm').format(notification.timestamp!) + : "No Date"; + + return Card( + elevation: 4.0, // Adjust the shadow's elevation + margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 0), // Spacing between cards + child: ListTile( + leading: Icon(notification.unread ?? false ? Icons.notifications_active : Icons.notifications_off), + title: Text(notification.verb ?? "No Title"), + subtitle: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + notification.description ?? "No Description", + overflow: TextOverflow.ellipsis, + ), + ), + Text(formattedDate, textAlign: TextAlign.right), + ], + ), + onTap: () { + // Handle tap + }, + ), + ); + }, + ), + + + ); + } + + @override + void dispose() { + _dashboardController.close(); + super.dispose(); + } +} \ No newline at end of file diff --git a/lib/screens/LoginandDashboard/dashboard.dart b/lib/screens/LoginandDashboard/dashboard.dart index 80c2719f..24f372d5 100644 --- a/lib/screens/LoginandDashboard/dashboard.dart +++ b/lib/screens/LoginandDashboard/dashboard.dart @@ -2,15 +2,17 @@ import 'dart:async'; import 'dart:convert'; import 'package:fusion/models/profile.dart'; import 'package:fusion/services/profile_service.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:fusion/Components/appBar.dart'; -import 'package:fusion/Components/side_drawer.dart'; +import 'package:fusion/Components/appBar2.dart'; +import 'package:fusion/Components/side_drawer2.dart'; import 'package:fusion/models/dashboard.dart'; import 'package:fusion/screens/LoginandDashboard/DashboardComponents/cardItems.dart'; import 'package:fusion/services/dashboard_service.dart'; import 'package:http/http.dart'; +import 'package:fusion/services/appBar_services.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; +import 'package:fusion/Components/bottom_navigation_bar.dart'; class Dashboard extends StatefulWidget { static String tag = 'home-page'; @@ -20,9 +22,11 @@ class Dashboard extends StatefulWidget { } class _DashboardState extends State { - bool _notificationsBool = true; + bool _notificationsBool = false; bool _newsBool = false; bool _announcementsBool = false; + bool _homeBool = true; + bool _loading = true; late String name; late String studentType; @@ -33,6 +37,12 @@ class _DashboardState extends State { late StreamController _profileController; late ProfileService profileService; late ProfileData data2; + late List designationsArray; + var service = locator(); + late String curr_desig = service.getFromDisk("Current_designation"); + bool isStudent = false; + + final appBarServices _appBarServices = appBarServices(); @override void initState() { super.initState(); @@ -45,17 +55,28 @@ class _DashboardState extends State { getData() async { try { + print("gfsgsgd"); Response response = await dashboardService.getDashboard(); + print("1"); Response response2 = await profileService.getProfile(); + print("2"); + print(response); + print(response2); + setState(() { data = DashboardData.fromJson(jsonDecode(response.body)); data2 = ProfileData.fromJson(jsonDecode(response2.body)); _loading = false; }); + print(data2.user!); + print( + '-----------------------------------=---------------------------------------'); name = data2.user!['first_name'] + ' ' + data2.user!['last_name']; - studentType = data2.profile!['department']!['name'] + - ' ' + - data2.profile!['user_type']; + studentType = data2.profile!['department']!['name']; + + if (data2.profile!['user_type'] == 'student') { + isStudent = true; + } } catch (e) { print(e); } @@ -68,6 +89,15 @@ class _DashboardState extends State { }); } + fetchDesignations() async { + try { + designationsArray = await _appBarServices.getDesignations(); + } catch (e) { + print("Error fetching designations: $e"); + return null; + } + } + final GlobalKey scaffoldKey = new GlobalKey(); showSnack() { ScaffoldMessenger.of(context).showSnackBar( @@ -80,174 +110,221 @@ class _DashboardState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: DefaultAppBar() - .buildAppBar(), // This is default app bar used in all modules - drawer: SideDrawer(), // This is sideDrawer used in all modules - body: _loading == true - ? Center(child: CircularProgressIndicator()) - : StreamBuilder( - stream: _dashboardController.stream, - builder: (context, AsyncSnapshot snapshot) { - return ListView( - shrinkWrap: true, - physics: ClampingScrollPhysics(), - children: [ - Card( - elevation: 2.0, - margin: EdgeInsets.symmetric( - horizontal: 50.0, vertical: 20.0), - shadowColor: Colors.black, - child: Column( + appBar: CustomAppBar( + curr_desig: curr_desig, + headerTitle: "Dashboard", + onDesignationChanged: (newValue) { + setState(() { + curr_desig = newValue; + }); + }, + ), // This is default app bar used in all modules + drawer: SideDrawer(curr_desig: curr_desig), + bottomNavigationBar: + MyBottomNavigationBar(), // This is sideDrawer used in all modules + body: Column( + children: [ + Expanded( + child: _loading == true + ? Center(child: CircularProgressIndicator()) + : StreamBuilder( + stream: _dashboardController.stream, + builder: (context, AsyncSnapshot snapshot) { + return ListView( + shrinkWrap: true, + physics: ClampingScrollPhysics(), children: [ - Container( - margin: EdgeInsets.only(top: 20.0), - width: 170.0, - height: 170.0, - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/profile_pic.png'), - fit: BoxFit.cover, - ), - ), - ), - SizedBox( - height: 10.0, - ), - Text( - name, //Display name of User - style: - TextStyle(fontSize: 20.0, color: Colors.black), - ), - SizedBox( - height: 10.0, - ), - Text( - studentType, // Display Type of User - style: - TextStyle(fontSize: 15.0, color: Colors.black), - ), - SizedBox( - height: 10.0, - ), - ], - ), - ), - Card( - color: Colors.black, - child: Padding( - padding: const EdgeInsets.all(10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - _notificationsBool = true; - _announcementsBool = false; - _newsBool = false; - setState(() { - _notificationsBool = true; - _announcementsBool = false; - _newsBool = false; - }); - }, - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Notifications', - style: TextStyle( - fontSize: 16.0, - color: Colors.white, + Card( + elevation: 2.0, + margin: EdgeInsets.symmetric( + horizontal: 20.0, vertical: 30.0), + // shadowColor: Colors.black, + color: Colors.white, + + child: Column( + children: [ + Container( + margin: EdgeInsets.only(top: 20.0), + width: 170.0, + height: 190.0, + decoration: BoxDecoration( + image: DecorationImage( + image: + AssetImage('assets/profile_pic.png'), + fit: BoxFit.cover, ), ), - Icon( - Icons.notifications_active_rounded, - color: _notificationsBool - ? Colors.deepOrangeAccent - : Colors.white, - ), - ], - ), + ), + SizedBox( + height: 10.0, + ), + Text( + name, //Display name of User + style: TextStyle( + fontSize: 20.0, + color: Colors.black, + fontWeight: FontWeight.bold), + ), + SizedBox( + height: 10.0, + ), + Text( + studentType + + " " + + curr_desig, // Display Type of User + style: TextStyle( + fontSize: 17.0, + color: Colors.black, + fontWeight: FontWeight.bold), + ), + SizedBox( + height: 10.0, + ), + ], ), - GestureDetector( - onTap: () { - _newsBool = true; - _announcementsBool = false; - _notificationsBool = false; - setState(() { - _newsBool = true; - _announcementsBool = false; - _notificationsBool = false; - }); - }, + ), + + Card( + margin: EdgeInsets.symmetric( + horizontal: 20.0, vertical: 10.0), + color: Colors.deepOrangeAccent, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + 50.0), // Set the border radius here + ), + child: Padding( + padding: const EdgeInsets.only( + top: 10.0, + bottom: 10.0, + left: 13.0, + right: 10.0), child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, + mainAxisAlignment: MainAxisAlignment + .spaceEvenly, // Align the children along the main axis with space between them + crossAxisAlignment: CrossAxisAlignment + .center, // Align the children along the cross axis (vertically by default) + // mainAxisSize: MainAxisSize.max, children: [ - Text( - 'News', - style: TextStyle( - fontSize: 16.0, - color: Colors.white, + GestureDetector( + onTap: () { + _notificationsBool = true; + _announcementsBool = false; + _newsBool = false; + setState(() { + _notificationsBool = true; + _announcementsBool = false; + _newsBool = false; + }); + Navigator.pushReplacementNamed( + context, "/profile"); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: [ + Icon( + Icons.account_circle, + color: Colors.white, + size: 30.0, + ), + SizedBox(width: 40.0), + Text( + 'Professsional Profile', + style: TextStyle( + fontSize: 20.0, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(width: 40.0), + Icon( + Icons.arrow_forward_ios_rounded, + color: Colors.white, + ), + ], ), ), - Icon( - Icons.email, - color: _newsBool - ? Colors.deepOrangeAccent - : Colors.white, - ), ], ), ), - GestureDetector( - onTap: () { - _announcementsBool = true; - _newsBool = false; - _notificationsBool = false; - setState(() { - _announcementsBool = true; - _newsBool = false; - _notificationsBool = false; - }); - }, + ), + + if (!isStudent) + Card( + margin: EdgeInsets.symmetric( + horizontal: 20.0, vertical: 10.0), + color: Colors.deepOrangeAccent, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + 50.0), // Set the border radius here + ), child: Padding( - padding: const EdgeInsets.only(right: 16.0), + padding: const EdgeInsets.only( + top: 10.0, + bottom: 10.0, + left: 13.0, + right: 10.0), child: Row( mainAxisAlignment: - MainAxisAlignment.spaceBetween, + MainAxisAlignment.spaceEvenly, children: [ - Text( - 'Announcements', - style: TextStyle( - fontSize: 16.0, - color: Colors.white, + GestureDetector( + onTap: () { + _notificationsBool = true; + _announcementsBool = false; + _newsBool = false; + setState(() { + _notificationsBool = true; + _announcementsBool = false; + _newsBool = false; + }); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment + .spaceEvenly, // Align the children along the main axis with space between them + crossAxisAlignment: CrossAxisAlignment + .center, // Align the children along the cross axis (vertically by default) + mainAxisSize: MainAxisSize.max, + children: [ + Icon( + Icons.notifications_active_rounded, + color: Colors.white, + ), + SizedBox(width: 40.0), + Text( + 'Admistrative Profile', + style: TextStyle( + fontSize: 20.0, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(width: 40.0), + Icon( + Icons.arrow_forward_ios_rounded, + color: Colors.white, + ), + ], ), ), - Icon( - Icons.announcement, - color: _announcementsBool - ? Colors.deepOrangeAccent - : Colors.white, - ), ], ), ), ), - ], - ), - ), - ), - _notificationsBool - ? NotificationCard( - notifications: data.notifications, - ) - : NewsCard(), - ], - ); - }, - ), + + // _notificationsBool + // ? NotificationCard( + // notifications: data.notifications, + // ) + // : NewsCard(), + ], + ); + }, + ), + ), + // Place the BottomNavigationBar here + ], + ), ); } @@ -256,4 +333,4 @@ class _DashboardState extends State { _dashboardController.close(); super.dispose(); } -} +} \ No newline at end of file diff --git a/lib/screens/LoginandDashboard/login_page.dart b/lib/screens/LoginandDashboard/login_page.dart index ca09fee2..aff38280 100644 --- a/lib/screens/LoginandDashboard/login_page.dart +++ b/lib/screens/LoginandDashboard/login_page.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:fusion/constants.dart'; @@ -10,7 +9,9 @@ class LoginPage extends StatefulWidget { _LoginPageState createState() => _LoginPageState(); } -bool checkBoxValue = false; +bool _focused = false; +bool _focused2 = false; +double bottom =10; class _LoginPageState extends State { final GlobalKey _formKey = GlobalKey(); @@ -23,21 +24,45 @@ class _LoginPageState extends State { final Widget logoWidget = CircleAvatar( backgroundColor: Colors.transparent, - radius: 54.0, - child: Image.asset('assets/logo.jpg'), + radius: (_focused || _focused2) ? 110.0 : 150.0, + child:Container( + + child: Image.asset('assets/logo.jpg'), + ), ); - final Widget emailFormField = TextFormField( + final Widget emailFormField = Focus( + onFocusChange: (focus) { + setState(() { + _focused = focus; + if (focus==true){ + bottom=400; + } + + }); + }, + child:TextFormField( keyboardType: TextInputType.emailAddress, autofocus: false, decoration: InputDecoration( label: Text('Username', style: TextStyle( - fontSize: 12.0, + fontSize: 18.0, ),), contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0), - border: OutlineInputBorder( - // borderRadius: BorderRadius.circular(32.0), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 0, color: Color(0xFFf4f4f4)), + borderRadius: BorderRadius.circular(20.0), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(width: 0, color: Color(0xFFf4f4f4)), + borderRadius: BorderRadius.circular(20.0), ), + // enabledBorder: InputBorder.none, + fillColor: Color(0xFFf4f4f4), // Green color + filled: true, + floatingLabelBehavior: FloatingLabelBehavior.never, ), + cursorColor: Colors.black, + onChanged: (input) { username = input; }, @@ -48,23 +73,45 @@ class _LoginPageState extends State { else if (value?.contains('@') == true) { return 'Please enter username only'; } + return null; }, autofillHints: [AutofillHints.username], - ); + )); + + final Widget passwordFormField = Focus( + onFocusChange: (focus) { + setState(() { + _focused2 = focus; + if (focus==true){ + bottom=400; + } - final Widget passwordFormField = TextFormField( + }); + }, + child: TextFormField( autofocus: false, obscureText: true, decoration: InputDecoration( label: Text('Password', style: TextStyle( - fontSize: 12.0, + fontSize: 18.0, ),), contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0), - border: OutlineInputBorder( - // borderRadius: BorderRadius.circular(32.0), + + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 0, color: Color(0xFFf4f4f4)), + borderRadius: BorderRadius.circular(20.0), ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(width: 0, color: Color(0xFFf4f4f4)), + borderRadius: BorderRadius.circular(20.0), + ), + // enabledBorder: InputBorder.none, + fillColor: Color(0xFFf4f4f4), // Green color + filled: true, + floatingLabelBehavior: FloatingLabelBehavior.never, ), + cursorColor: Colors.black, onChanged: (input) { pass = input; }, @@ -74,12 +121,13 @@ class _LoginPageState extends State { } else if (value.length < 6) { return 'Password must be at least 6 characters'; } + return null; }, autofillHints: [AutofillHints.password], - ); + )); final loginButton = Padding( - padding: EdgeInsets.symmetric(vertical: 16.0), + padding: EdgeInsets.only(top: 16.0), child: ElevatedButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all(kPrimaryColor), @@ -102,7 +150,8 @@ class _LoginPageState extends State { style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, - fontSize: 14.0, + fontSize: 22.0, + ), ), ), @@ -124,13 +173,16 @@ class _LoginPageState extends State { key: _formKey, child: ListView( shrinkWrap: true, - padding: EdgeInsets.only(left: 24.0, right: 24.0), + padding: EdgeInsets.only(top:8.0,left: 24.0, right: 24.0), children: [ - logoWidget, + Padding( + padding: const EdgeInsets.only(top: 0.0), // Change the top padding here + child: logoWidget, + ), Padding( padding: const EdgeInsets.only(bottom: 30.0), child: Text( - 'Fusion Login', + 'Fusion', style: TextStyle( color: kPrimaryColor, fontWeight: FontWeight.bold, @@ -141,14 +193,21 @@ class _LoginPageState extends State { ), Padding( padding: EdgeInsets.only(bottom: 15), - child: emailFormField, + child: emailFormField, ), Padding( padding: EdgeInsets.only(bottom: 15), child: passwordFormField, ), - loginButton, - forgotLabel, + Padding( + padding: EdgeInsets.only(bottom: 0.0), + child: loginButton, + ), + Padding( + padding: EdgeInsets.only(top:0.0,bottom: bottom), + child: forgotLabel, + ), + ], ), ), @@ -157,29 +216,29 @@ class _LoginPageState extends State { ); } - // void _showDialog() { - // // flutter defined function - // showDialog( - // context: context, - // builder: (BuildContext context) { - // // return object of type Dialog - // return AlertDialog( - // title: Text("Invalid Username/Password"), - // content: Text("Please enter correct Username or Password"), - // actions: [ - // // usually buttons at the bottom of the dialog - // new TextButton( - // child: new Text( - // "Close", - // style: TextStyle(color: Colors.deepOrangeAccent), - // ), - // onPressed: () { - // Navigator.of(context).pop(); - // }, - // ), - // ], - // ); - // }, - // ); - // } -} +// void _showDialog() { +// // flutter defined function +// showDialog( +// context: context, +// builder: (BuildContext context) { +// // return object of type Dialog +// return AlertDialog( +// title: Text("Invalid Username/Password"), +// content: Text("Please enter correct Username or Password"), +// actions: [ +// // usually buttons at the bottom of the dialog +// new TextButton( +// child: new Text( +// "Close", +// style: TextStyle(color: Colors.deepOrangeAccent), +// ), +// onPressed: () { +// Navigator.of(context).pop(); +// }, +// ), +// ], +// ); +// }, +// ); +// } +} \ No newline at end of file diff --git a/lib/screens/Profile/Menus/achievements_menu.dart b/lib/screens/Profile/Menus/achievements_menu.dart index e52a613c..d0cfaef2 100644 --- a/lib/screens/Profile/Menus/achievements_menu.dart +++ b/lib/screens/Profile/Menus/achievements_menu.dart @@ -238,7 +238,7 @@ class AchievementsMenu extends StatelessWidget { //Edit Function }, style: ElevatedButton.styleFrom( - primary: Colors.red, + backgroundColor: Colors.red, ), ), ], diff --git a/lib/screens/Profile/Menus/education_menu.dart b/lib/screens/Profile/Menus/education_menu.dart index 6d3e42d0..5f1d84f0 100644 --- a/lib/screens/Profile/Menus/education_menu.dart +++ b/lib/screens/Profile/Menus/education_menu.dart @@ -402,7 +402,7 @@ class EducationMenu extends StatelessWidget { onPressed: () => { //Edit Function }, - style: ElevatedButton.styleFrom(primary: Colors.red), + style: ElevatedButton.styleFrom(backgroundColor: Colors.red), ), ], ), @@ -722,7 +722,7 @@ class EducationMenu extends StatelessWidget { onPressed: () => { //Edit Function }, - style: ElevatedButton.styleFrom(primary: Colors.red), + style: ElevatedButton.styleFrom(backgroundColor: Colors.red), ), ], ), diff --git a/lib/screens/Profile/Menus/profile_menu.dart b/lib/screens/Profile/Menus/profile_menu.dart index b7a94404..352fb5bd 100644 --- a/lib/screens/Profile/Menus/profile_menu.dart +++ b/lib/screens/Profile/Menus/profile_menu.dart @@ -37,7 +37,7 @@ class ProfileMenu extends StatelessWidget { onPressed: () => { //Edit Function }, - style: ElevatedButton.styleFrom(primary: Colors.red)), + style: ElevatedButton.styleFrom(backgroundColor: Colors.red)), ], ), ), @@ -90,7 +90,7 @@ class ProfileMenu extends StatelessWidget { onPressed: () => { //Edit Function }, - style: ElevatedButton.styleFrom(primary: Colors.red), + style: ElevatedButton.styleFrom(backgroundColor: Colors.red), ), ], ), @@ -226,7 +226,7 @@ class ProfileMenu extends StatelessWidget { onPressed: () => { //Edit Function }, - style: ElevatedButton.styleFrom(primary: Colors.red), + style: ElevatedButton.styleFrom(backgroundColor: Colors.red), ), ], ), diff --git a/lib/screens/Profile/Menus/skills_menu.dart b/lib/screens/Profile/Menus/skills_menu.dart index 4f9ab448..9101a792 100644 --- a/lib/screens/Profile/Menus/skills_menu.dart +++ b/lib/screens/Profile/Menus/skills_menu.dart @@ -172,7 +172,7 @@ class SkillsMenu extends StatelessWidget { //Edit Function }, style: ElevatedButton.styleFrom( - primary: Colors.red, + backgroundColor: Colors.red, ), ), ], diff --git a/lib/screens/Profile/Menus/work_experiences_menu.dart b/lib/screens/Profile/Menus/work_experiences_menu.dart index 02f5a801..cfb08a1f 100644 --- a/lib/screens/Profile/Menus/work_experiences_menu.dart +++ b/lib/screens/Profile/Menus/work_experiences_menu.dart @@ -440,7 +440,7 @@ class WorkExperiencesMenu extends StatelessWidget { onPressed: () => { //Edit Function }, - style: ElevatedButton.styleFrom(primary: Colors.red), + style: ElevatedButton.styleFrom(backgroundColor: Colors.red), ), ], ), @@ -805,7 +805,7 @@ class WorkExperiencesMenu extends StatelessWidget { onPressed: () => { //Edit Function }, - style: ElevatedButton.styleFrom(primary: Colors.red), + style: ElevatedButton.styleFrom(backgroundColor: Colors.red), ), ], ), diff --git a/lib/services/appBar_services.dart b/lib/services/appBar_services.dart new file mode 100644 index 00000000..bc7ba3c0 --- /dev/null +++ b/lib/services/appBar_services.dart @@ -0,0 +1,14 @@ +import 'package:fusion/services/storage_service.dart'; + +class appBarServices { + getDesignations() async { + try { + var storageService = await StorageService.getInstance(); + List? designations = storageService!.getFromDisk('designations'); + + return designations; + } catch (e) { + rethrow; + } + } +} \ No newline at end of file diff --git a/lib/services/dashboard_service.dart b/lib/services/dashboard_service.dart index 8e4520a9..ef348125 100644 --- a/lib/services/dashboard_service.dart +++ b/lib/services/dashboard_service.dart @@ -7,12 +7,12 @@ import 'package:http/http.dart' as http; class DashboardService { getDashboard() async { try { - var storage_service = locator(); - if (storage_service.userInDB?.token == null) + var storageService = locator(); + if (storageService.userInDB?.token == null) throw Exception('Token Error'); Map headers = { - 'Authorization': 'Token ' + (storage_service.userInDB?.token ?? "") + 'Authorization': 'Token ' + (storageService.userInDB?.token ?? "") }; var client = http.Client(); http.Response response = await client.get( @@ -24,6 +24,43 @@ class DashboardService { ); if (response.statusCode == 200) { print("success"); + print(response); + return response; + } + throw Exception('Can\'t load'); + } catch (e) { + rethrow; + } + } + + + getNotification() async { + try { + print("gett"); + var storageService = locator(); + if (storageService.userInDB?.token == null) + throw Exception('Token Error'); + + + Map headers = { + 'Authorization': 'Token ' + (storageService.userInDB?.token ?? "") + }; + print("gett2"); + + var client = http.Client(); + http.Response response = await client.get( + Uri.http( + getLink(), + kNotification, // constant dashboard path + ), + headers: headers, + ); + + print("gett3"); + + if (response.statusCode == 200) { + print("success"); + print(response); return response; } throw Exception('Can\'t load'); @@ -34,12 +71,12 @@ class DashboardService { markRead(String id) async { try { - StorageService? storage_service = await StorageService.getInstance(); + StorageService? storageService = await StorageService.getInstance(); - if (storage_service?.userInDB?.token == null) + if (storageService?.userInDB?.token == null) throw Exception('Token Error'); - String token = storage_service?.userInDB?.token ?? ""; + String token = storageService?.userInDB?.token ?? ""; Map headers = {'Authorization': 'Token ' + token}; Map body = {"id": id}; var client = http.Client(); @@ -60,4 +97,4 @@ class DashboardService { rethrow; } } -} +} \ No newline at end of file diff --git a/lib/services/department_service.dart b/lib/services/department_service.dart new file mode 100644 index 00000000..c32c546a --- /dev/null +++ b/lib/services/department_service.dart @@ -0,0 +1,331 @@ +import 'dart:convert'; +import 'package:fusion/api.dart'; +import 'package:fusion/constants.dart'; +import 'package:http/http.dart' as http; +import 'package:http_parser/http_parser.dart'; +import 'package:fusion/services/service_locator.dart'; +import 'package:fusion/services/storage_service.dart'; + +class Student { + final String id; + final String programme; + final int batch; + final double cpi; + final String category; + final String fatherName; + final String motherName; + final int hallNo; + final int? roomNo; + final String specialization; + final int currSemesterNo; + final int batchId; + + Student({ + required this.id, + required this.programme, + required this.batch, + required this.cpi, + required this.category, + required this.fatherName, + required this.motherName, + required this.hallNo, + required this.roomNo, + required this.specialization, + required this.currSemesterNo, + required this.batchId, + }); + + factory Student.fromJson(Map json) { + return Student( + id: json['id'] ?? '', + programme: json['programme'] ?? '', + batch: json['batch'] ?? 0, + cpi: json['cpi'] != null ? json['cpi'].toDouble() : 0.0, + category: json['category'] ?? '', + fatherName: json['father_name'] ?? '', + motherName: json['mother_name'] ?? '', + hallNo: json['hall_no'] ?? 0, + roomNo: json['room_no'], + specialization: json['specialization'] ?? '', + currSemesterNo: json['curr_semester_no'] ?? 0, + batchId: json['batch_id'] ?? 0, + ); + } +} + +class FacultyDetails { + final String id; + final String title; + final String sex; + final String dateOfBirth; + final String userStatus; + final String address; + final String userType; + final String profilePicture; + final String aboutMe; + final String dateModified; + final int phoneNumber; + final int user; + final int department; + + FacultyDetails({ + required this.id, + required this.title, + required this.sex, + required this.dateOfBirth, + required this.userStatus, + required this.address, + required this.phoneNumber, + required this.userType, + required this.profilePicture, + required this.aboutMe, + required this.dateModified, + required this.user, + required this.department, + }); + + factory FacultyDetails.fromJson(Map json) { + return FacultyDetails( + id: json['id'] ?? '', + title: json['title'] ?? '', + sex: json['sex'] ?? '', + dateOfBirth: json['date_of_birth'] ?? '', + userStatus: json['user_status'] ?? '', + address: json['address'] ?? '', + phoneNumber: json['phone_no'] ?? '', + userType: json['user_type'] ?? '', + profilePicture: json['profile_picture'] ?? '', + aboutMe: json['about_me'] ?? '', + dateModified: json['date_modified'] ?? '', + user: json['user'] ?? 0, + department: json['department'] ?? 0, + ); + } + + get entries => null; +} + +class Announcement { + final String ann_date; + final String maker_id; + final String programme; + final String batch; + final String department; + final String message; + final String? upload_announcement; + + Announcement({ + required this.ann_date, + required this.maker_id, + required this.programme, + required this.batch, + required this.department, + required this.message, + this.upload_announcement, + }); + + factory Announcement.fromJson(Map json) { + return Announcement( + ann_date: json['ann_date'], + maker_id: json['maker_id'], + programme: json['programme'], + batch: json['batch'], + department: json['department'], + message: json['message'], + upload_announcement: json['upload_announcement'], + ); + } +} + +class DepartmentService { + // Future> fetchDepartmentInfo(String departmentId) async { + // try { + // var storage_service = locator(); + // if (storage_service.userInDB?.token == null) + // throw Exception('Token Error'); + + // Map headers = { + // 'Authorization': 'Token ' + (storage_service.userInDB?.token ?? "") + // }; + + // http.Response response = await http.get( + // Uri.http(getLink(), kDepartmentInfo), + // headers: headers, + // ); + // if (response.statusCode == 200) { + // Map departmentInfo = jsonDecode(response.body); + // return departmentInfo; + // } else { + // throw Exception('Failed to fetch department information.'); + // } + // } catch (e) { + // print('Error in fetchDepartmentInfo: $e'); + // rethrow; + // } + // } + + Future>> getFacultyDetails( + String department) async { + try { + var storage_service = locator(); + if (storage_service.userInDB?.token == null) + throw Exception('Token Error'); + + Map headers = { + 'Authorization': 'Token ' + (storage_service.userInDB?.token ?? "") + }; + + http.Response response = await http.get( + Uri.http(getLink(), kDepMain), + headers: headers, + ); + if (response.statusCode == 200) { + Map jsonData = json.decode(response.body); + List> facultyList = []; + List>? departmentFacultyList = jsonData['fac_list'] + ?[department.toLowerCase() + '_f'] + ?.cast>(); + facultyList.addAll(departmentFacultyList ?? []); + // print(facultyList); + return facultyList; + } else { + throw Exception('Failed to load faculty details for $department'); + } + } catch (e) { + print('Error in getFacultyDetails: $e'); + rethrow; + } + } + + Future> getDepartmentsAnnouncements( + String department) async { + try { + var storage_service = locator(); + if (storage_service.userInDB?.token == null) + throw Exception('Token Error'); + + Map headers = { + 'Authorization': 'Token ' + (storage_service.userInDB?.token ?? "") + }; + + http.Response response = await http.get( + Uri.http(getLink(), kDepMain), + headers: headers, + ); + + if (response.statusCode == 200) { + Map jsonData = json.decode(response.body); + List departmentAnnouncements = []; + if (department.toLowerCase() == 'all') { + departmentAnnouncements.addAll(jsonData['announcements']['all']); + departmentAnnouncements.addAll(jsonData['announcements']['cse']); + departmentAnnouncements.addAll(jsonData['announcements']['ece']); + departmentAnnouncements.addAll(jsonData['announcements']['me']); + departmentAnnouncements.addAll(jsonData['announcements']['sm']); + } else { + departmentAnnouncements = + jsonData['announcements'][department.toLowerCase()]; + } + // print(departmentAnnouncements); + List announcements = departmentAnnouncements.map((item) { + return Announcement.fromJson(item); + }).toList(); + return announcements; + } else { + throw Exception('Failed to load announcements for $department'); + } + } catch (e) { + print('Error in getAnnouncements: $e'); + rethrow; + } + } + + Future createAnnouncement(Map announcementData) async { + try { + var storage_service = locator(); + if (storage_service.userInDB?.token == null) { + throw Exception('Token Error'); + } + + Map headers = { + 'Authorization': 'Token ' + (storage_service.userInDB?.token ?? ""), + }; + + if (announcementData['upload_announcement'] != null) { + var request = http.MultipartRequest( + 'POST', + Uri.http(getLink(), kDepMain), + ); + + request.headers.addAll(headers); + announcementData.forEach((key, value) { + if (key != 'upload_announcement') { + request.fields[key] = value.toString(); + } + }); + var multipartFile = await http.MultipartFile.fromPath( + 'upload_announcement', + announcementData['upload_announcement'], + contentType: MediaType('file', 'pdf,jpeg,png,jpg'), + ); + + request.files.add(multipartFile); + print(request); + var response = await http.Response.fromStream(await request.send()); + if (response.statusCode == 201) { + return true; + } else { + return false; + } + } else { + headers['Content-Type'] = 'application/json'; + http.Response response = await http.post( + Uri.http(getLink(), kDepartmentAnnouncements), + headers: headers, + body: jsonEncode(announcementData), + ); + + if (response.statusCode == 201) { + return true; + } else { + return false; + } + } + } catch (e) { + print('Exception occurred while creating announcement: $e'); + return false; + } + } + + Future>> getStudents(int bid) async { + try { + var storage_service = locator(); + if (storage_service.userInDB?.token == null) { + throw Exception('Token Error'); + } + + Map headers = { + 'Authorization': 'Token ' + (storage_service.userInDB?.token ?? "") + }; + + http.Response response = await http.get( + Uri.http(getLink(), '$kAllStudents$bid'), + headers: headers, + ); + print('$kAllStudents$bid'); + if (response.statusCode == 200) { + Map jsonResponse = json.decode(response.body); + List> studentList = + jsonResponse['student_list'].cast>(); + print(studentList); + return studentList; + } else { + print('Failed to get students. Error: ${response.statusCode}'); + return []; + } + } catch (e) { + print('Exception occurred while getting students: $e'); + return []; + } + } +} diff --git a/lib/services/login_service.dart b/lib/services/login_service.dart index 17d79b42..97277ffc 100644 --- a/lib/services/login_service.dart +++ b/lib/services/login_service.dart @@ -1,6 +1,5 @@ import 'dart:convert'; -import 'package:fusion/constants.dart'; import 'package:fusion/api.dart'; import 'package:fusion/models/user.dart'; import 'package:fusion/services/storage_service.dart'; @@ -25,8 +24,15 @@ class LoginService { var prefs = await StorageService.getInstance(); print("response.body: ${response.body}"); - var storage_service = await StorageService.getInstance(); - storage_service!.saveUserInDB(User((jsonDecode(response.body))["token"])); + var storageService = await StorageService.getInstance(); + storageService!.saveUserInDB(User((jsonDecode(response.body))["token"])); + storageService.saveToDisk>( + 'designations', + (jsonDecode(response.body)["designations"] as List) + .map((dynamic item) => item.toString()) + .toList(), + ); + storageService.saveStringToDisk("Current_designation",jsonDecode(response.body)["designations"][0]); return true; } catch (e) { rethrow; @@ -35,8 +41,8 @@ class LoginService { void logout() async { try { - var storage_service = await StorageService.getInstance(); - storage_service!.deleteKey("user"); + var storageService = await StorageService.getInstance(); + storageService!.deleteKey("user"); } catch (e) { rethrow; } diff --git a/lib/services/storage_service.dart b/lib/services/storage_service.dart index 94d39ea4..9d118326 100644 --- a/lib/services/storage_service.dart +++ b/lib/services/storage_service.dart @@ -13,19 +13,19 @@ class StorageService with ChangeNotifier { static const String ProfileKey = "ProfileKey"; User? get userInDB { - var userJson = _getFromDisk(UserKey); + var userJson = getFromDisk(UserKey); return userJson == null ? null : User.fromJson(jsonDecode(userJson)); } ProfileData get profileData { - var profileJson = _getFromDisk(ProfileKey); + var profileJson = getFromDisk(ProfileKey); // print(jsonDecode(profileJson)); return ProfileData.fromJson(jsonDecode(profileJson)); } AcademicData get academicData { - var profileJson = _getFromDisk(ProfileKey); + var profileJson = getFromDisk(ProfileKey); // print(jsonDecode(profileJson)); return AcademicData.fromJson(jsonDecode(profileJson)); } @@ -49,9 +49,9 @@ class StorageService with ChangeNotifier { return _instance; } - dynamic _getFromDisk(String key) { + dynamic getFromDisk(String key) { var value = _sharedPreferences?.get(key); - // print('(TRACE) LocalStorageService:_getFromDisk. key: $key value: $value'); + // print('(TRACE) LocalStorageService:getFromDisk. key: $key value: $value'); return value; } @@ -62,7 +62,7 @@ class StorageService with ChangeNotifier { void deleteKey(String key) { print( - '(TRACE) StorageService: deleteKey. key: $key value: ${_getFromDisk(key)}'); + '(TRACE) StorageService: deleteKey. key: $key value: ${getFromDisk(key)}'); _sharedPreferences!.remove(key); } @@ -84,4 +84,4 @@ class StorageService with ChangeNotifier { _sharedPreferences!.setStringList(key, content); } } -} +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 49030f0b..f9d06ea4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,8 +39,9 @@ dependencies: path_provider: ^2.0.8 open_file: ^3.2.1 flutter_html: ^2.2.1 - - + file_selector: ^1.0.3 + file_picker: ^3.0.4 + webview_flutter: ^2.8.0 dev_dependencies: flutter_test: