You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mohemm-flutter-app/lib/ui/attendance/monthly_attendance.dart

805 lines
32 KiB
Dart

import 'package:easy_localization/easy_localization.dart';
import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:mohem_flutter_app/api/monthlyAttendance_api_client.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/models/get_day_hours_type_details_list_model.dart';
import 'package:mohem_flutter_app/models/get_schedule_shifts_details_list_model.dart';
import 'package:mohem_flutter_app/models/get_time_card_summary_list_model.dart';
import 'package:mohem_flutter_app/widgets/circular_step_progress_bar.dart';
import 'package:provider/provider.dart';
import 'package:syncfusion_flutter_calendar/calendar.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:flutter/cupertino.dart';
import 'package:pie_chart/pie_chart.dart';
class MonthlyAttendance extends StatefulWidget {
MonthlyAttendance({Key? key}) : super(key: key);
@override
_MonthlyAttendanceState createState() {
return _MonthlyAttendanceState();
}
}
class _MonthlyAttendanceState extends State<MonthlyAttendance> {
bool isPresent = true;
bool isAbsent = true;
bool isMissingDays = true;
bool isOffDays = true;
DateTime date = DateTime.now();
late var formattedDate;
var currentMonth = DateTime.now().month;
String searchMonth = getMonth(DateTime.now().month);
int searchYear = DateTime.now().year;
int? pRTPID;
List<GetDayHoursTypeDetailsList> getDayHoursTypeDetailsList = [];
GetTimeCardSummaryList? getTimeCardSummaryList;
// GetDayHoursTypeDetailsList? getDayHoursTypeDetailsList;
GetScheduleShiftsDetailsList? getScheduleShiftsDetailsList;
@override
void initState() {
super.initState();
getTimeCardSummary(searchMonth, searchYear);
getDayHoursTypeDetails(date.day, searchMonth, searchYear);
formattedDate = DateFormat('MMM-yyyy').format(date);
}
void getTimeCardSummary(searchMonth, searchYear) async {
try {
Utils.showLoading(context);
getTimeCardSummaryList = await MonthlyAttendanceApiClient().getTimeCardSummary(searchMonth, searchYear);
Utils.hideLoading(context);
setState(() {});
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
}
void getDayHoursTypeDetails(index, searchMonth, searchYear) async {
try {
Utils.showLoading(context);
getDayHoursTypeDetailsList = await MonthlyAttendanceApiClient().getDayHoursTypeDetails(searchMonth, searchYear);
Utils.hideLoading(context);
pRTPID = getDayHoursTypeDetailsList[index].rTPID;
setState(() {});
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
countAllAttendDays();
getScheduleShiftsDetails(pRTPID);
}
getScheduleShiftsDetails(pRTPID) async {
try {
Utils.showLoading(context);
getScheduleShiftsDetailsList = await MonthlyAttendanceApiClient().getScheduleShiftsDetails(pRTPID);
Utils.hideLoading(context);
setState(() {});
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
}
countAllAttendDays() {
// print(getDayHoursTypeDetailsList.length);
for (int i = 0; i < getDayHoursTypeDetailsList.length; i++) {
if (getDayHoursTypeDetailsList[i].aTTENDEDFLAG == 'Y') {
isPresent = true;
isAbsent = false;
isMissingDays = false;
isOffDays = false;
} else if (getDayHoursTypeDetailsList[i].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[i].aBSENTFLAG == 'Y') {
isPresent = false;
isAbsent = true;
isMissingDays = false;
isOffDays = false;
} else if (getDayHoursTypeDetailsList[i].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[i].dAYTYPE == 'OFF') {
isPresent = false;
isAbsent = false;
isMissingDays = false;
isOffDays = true;
} else {
isPresent = false;
isAbsent = false;
isMissingDays = true;
isOffDays = false;
}
}
}
final CalendarController _calendarController = CalendarController();
final List<Color> _colorList = [Color(0xff2AB2AB), Color(0xff202529)];
@override
Widget build(BuildContext context) {
Map<String, double> dataMap = {
"Present": getTimeCardSummaryList!.aTTENDEDDAYS!.toDouble(),
"Absent": getTimeCardSummaryList!.aBSENTDAYS!.toDouble(),
};
return Scaffold(
appBar: AppBar(
backgroundColor: MyColors.white,
leading: IconButton(
icon: const Icon(
Icons.arrow_back_ios,
color: MyColors.backgroundBlackColor,
),
onPressed: () => Navigator.pop(context),
),
),
backgroundColor: Colors.white,
body: ListView(
scrollDirection: Axis.vertical,
children: [
Column(
children: [
20.height,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Attendance".toText24(isBold: true, color: MyColors.darkIconColor),
Row(
children: [
Text(formattedDate),
const Icon(Icons.keyboard_arrow_down_rounded, color: MyColors.greyACColor),
],
).onPress(() async {
await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2021),
lastDate: DateTime.now(),
builder: (context, child) {
return Theme(
data: ThemeData.dark().copyWith(
colorScheme: const ColorScheme.dark(
primary: MyColors.lightGreenColor,
onPrimary: MyColors.white,
surface: MyColors.lightGreenColor,
onSurface: MyColors.darkTextColor,
),
dialogBackgroundColor: Colors.white,
),
child: child!,
);
},
).then((selectedDate) {
if (selectedDate != null) {
var selectedMonth = DateFormat('MMMM').format(selectedDate);
var selectedYear = DateFormat('yyyy').format(selectedDate);
searchMonth = selectedMonth;
searchYear = int.parse(selectedYear);
setState(() {
// date = selectedDate;
formattedDate = DateFormat('MMMM-yyyy').format(selectedDate);
getTimeCardSummary(searchMonth, searchYear);
getDayHoursTypeDetails(selectedDate.day, searchMonth, searchYear);
});
}
});
})
],
).paddingOnly(left: 21, right: 21),
18.height,
AspectRatio(aspectRatio: 333 / 270, child: calendarWidget()).paddingOnly(left: 21, right: 21),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
optionUI("Schedule\nDays", "${getTimeCardSummaryList!.sCHEDULEDAYS}"),
6.width,
optionUI("Off\nDays", "${getTimeCardSummaryList!.oFFDAYS}"),
6.width,
optionUI("Non\nAnalyzed", "${getTimeCardSummaryList!.uNAUTHORIZEDLEAVE}"),
6.width,
optionUI("Shortage\nHour", "${getTimeCardSummaryList!.sHORTAGEHRS}"),
],
).paddingOnly(left: 21, right: 21),
35.height,
Container(
width: double.infinity,
height: 227,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)),
boxShadow: [
BoxShadow(
offset: const Offset(0, 2),
blurRadius: 26,
color: MyColors.darkColor.withOpacity(0.1),
),
],
),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Column(
children: [
"Attendance".toText12(isBold: true, color: MyColors.grey3AColor),
"Stats".toText24(isBold: true, color: MyColors.grey3AColor),
],
).paddingOnly(left: 21, top: 29, bottom: 36),
Row(
children: [
Container(
height: 9,
width: 9,
decoration: BoxDecoration(
color: MyColors.lightGreenColor,
borderRadius: BorderRadius.circular(100),
),
),
Container(
margin: const EdgeInsets.only(left: 5, right: 5),
child: "PRESENT ${getTimeCardSummaryList!.aTTENDEDDAYS}".toText16(isBold: true, color: MyColors.lightGreenColor),
),
],
).paddingOnly(left: 21, right: 23),
8.height,
Row(
children: [
Container(
height: 9,
width: 9,
decoration: BoxDecoration(
color: MyColors.backgroundBlackColor,
borderRadius: BorderRadius.circular(100),
),
),
Container(
margin: const EdgeInsets.only(left: 5, right: 5),
child: "ABSENT ${getTimeCardSummaryList!.aBSENTDAYS}".toText16(
isBold: true,
color: MyColors.backgroundBlackColor,
),
)
],
).paddingOnly(left: 21, top: 8),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 169,
height: 170,
child: PieChart(
dataMap: dataMap,
animationDuration: const Duration(milliseconds: 800),
chartLegendSpacing: 0,
chartRadius: MediaQuery.of(context).size.width / 5.2,
colorList: _colorList,
initialAngleInDegree: 0,
chartType: ChartType.ring,
ringStrokeWidth: 80,
legendOptions: const LegendOptions(
showLegendsInRow: false,
showLegends: false,
),
chartValuesOptions: const ChartValuesOptions(
showChartValueBackground: false,
showChartValues: true,
showChartValuesInPercentage: true,
showChartValuesOutside: false,
decimalPlaces: 1,
chartValueStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: MyColors.white,
)),
),
),
],
).paddingOnly(left: 65, top: 27, right: 21, bottom: 28),
],
),
),
],
),
],
),
);
}
Widget optionUI(String title, String value) {
return AspectRatio(
aspectRatio: 1 / 1,
child: Container(
padding: const EdgeInsets.only(top: 10, left: 8, right: 8, bottom: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
offset: const Offset(0, 1),
blurRadius: 15,
color: MyColors.darkColor.withOpacity(0.1),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[title.toText10(color: MyColors.darkTextColor).expanded, value.toText20(color: MyColors.darkTextColor)],
),
),
).expanded;
}
Widget calendarWidget() {
return SfCalendar(
view: CalendarView.month,
// onViewChanged: viewChanged,
controller: _calendarController,
headerHeight: 0,
todayHighlightColor: MyColors.grey3AColor,
viewHeaderStyle: const ViewHeaderStyle(
dayTextStyle: TextStyle(color: MyColors.grey3AColor, fontSize: 13, fontWeight: FontWeight.w600),
),
monthCellBuilder: (cxt, build) {
int val = build.date.day;
val == countAllAttendDays();
if (isPresent) {
return Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
gradient: const LinearGradient(
transform: GradientRotation(.46),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor],
),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
offset: const Offset(0, 2),
blurRadius: 26,
color: MyColors.blackColor.withOpacity(0.100),
),
],
),
alignment: Alignment.center,
child: Text(
"${build.date.day}",
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: MyColors.white,
),
),
);
} else if (isAbsent) {
return Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: MyColors.backgroundBlackColor,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
offset: const Offset(0, 2),
blurRadius: 26,
color: MyColors.blackColor.withOpacity(0.100),
),
],
),
alignment: Alignment.center,
child: Text(
"${build.date.day}",
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: MyColors.white,
),
),
);
} else if (isMissingDays) {
return Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(color: MyColors.backgroundBlackColor, width: 2.0, style: BorderStyle.solid), //Border.all
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
offset: const Offset(0, 2),
blurRadius: 26,
color: MyColors.blackColor.withOpacity(0.100),
),
],
),
alignment: Alignment.center,
child: Text(
"${build.date.day}",
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: Color(0xff1F2428),
),
),
);
} else if (isOffDays) {
return Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: MyColors.greyACColor.withOpacity(.12),
shape: BoxShape.circle,
),
alignment: Alignment.center,
child: Text(
"${build.date.day}",
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: MyColors.greyA5Color,
),
),
);
} else {
return Container();
}
},
monthViewSettings: const MonthViewSettings(
dayFormat: 'EEE',
showTrailingAndLeadingDates: false,
appointmentDisplayMode: MonthAppointmentDisplayMode.appointment,
showAgenda: false,
navigationDirection: MonthNavigationDirection.horizontal,
monthCellStyle: MonthCellStyle(
textStyle: TextStyle(
fontStyle: FontStyle.normal,
fontSize: 13,
color: Colors.white,
),
),
),
showNavigationArrow: false,
showDatePickerButton: false,
showCurrentTimeIndicator: false,
showWeekNumber: false,
cellBorderColor: Colors.white,
selectionDecoration: BoxDecoration(
border: Border.all(color: MyColors.white, width: 10),
borderRadius: const BorderRadius.all(Radius.circular(100)),
shape: BoxShape.circle,
),
dataSource: MeetingDataSource(_getDataSource()),
onTap: calendarTapped,
);
}
calendarTapped(CalendarTapDetails details) {
dynamic string = getScheduleShiftsDetailsList!.pERCENTAGE;
dynamic percentage = string!.indexOf('%');
print(percentage);
print(details.date?.day.toString());
int? index = details.date?.day;
if (index != null) {
index = index - 1;
}
getDayHoursTypeDetails(index, getMonth(details.date!.month), details.date?.year);
showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)),
isScrollControlled: true,
backgroundColor: MyColors.backgroundBlackColor,
builder: (_) {
return DraggableScrollableSheet(
maxChildSize: 0.9,
expand: false,
builder: (_, controller) {
return Column(
children: [
Container(
width: 75,
height: 7,
margin: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: MyColors.darkGreyColor,
),
),
Expanded(
child: ListView.builder(
controller: controller,
itemCount: 1,
itemBuilder: (_, i) => Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.vertical(
top: Radius.circular(35.0),
),
color: MyColors.backgroundBlackColor,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(children: [
"${getScheduleShiftsDetailsList!.sCHEDULEDATE!.substring(0, 9)}".toText24(isBold: true, color: Colors.white),
"Attendance Details".tr().toText16(color: MyColors.lightGreyEFColor),
21.height,
]).paddingOnly(top: 25, left: 21, right: 21, bottom: 10),
Center(
child: CircularStepProgressBar(
totalSteps: 16 * 4,
currentStep: percentage,
width: 210,
height: 210,
selectedColor: MyColors.gradiantEndColor,
unselectedColor: MyColors.grey70Color,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
"${getScheduleShiftsDetailsList!.pERCENTAGE}".toText44(color: Colors.white, isBold: true),
"Completed".tr().toText11(color: MyColors.greyACColor),
19.height,
"Shift Time".tr().toText11(color: MyColors.greyACColor),
"${getScheduleShiftsDetailsList!.sHTNAME}".toText22(color: Colors.white, isBold: true),
],
),
),
),
),
Container(
padding: const EdgeInsets.only(top: 20, bottom: 20),
),
Stack(
children: [
Container(
height: 5,
padding: const EdgeInsets.only(top: 24, bottom: 24),
color: MyColors.backgroundBlackColor,
),
Container(
width: double.infinity,
decoration: const BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white),
padding: const EdgeInsets.only(left: 21, right: 21, top: 28, bottom: 24),
child: Column(
children: [
Row(
children: [
Container(
margin: const EdgeInsets.only(right: 30, left: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Actual Check In ".tr().toText11(
color: MyColors.grey67Color,
),
8.height,
"${getScheduleShiftsDetailsList!.sHTACTUALSTARTTIME}".toText22(color: Colors.black, isBold: true),
],
),
),
40.width,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Actual Check Out".tr().toText11(
color: MyColors.grey67Color,
),
8.height,
"${getScheduleShiftsDetailsList!.sHTACTUALENDTIME}".toText22(color: Colors.black, isBold: true),
],
),
],
),
25.height,
const Divider(
height: 1,
thickness: 1,
color: MyColors.whiteColor,
),
25.height,
Row(
children: [
Container(
margin: const EdgeInsets.only(right: 30, left: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Approved Check In".tr().toText11(
color: MyColors.grey67Color,
),
8.height,
"${getScheduleShiftsDetailsList!.aPPROVEDSTARTTIME}".toText22(color: MyColors.greenColor, isBold: true),
],
),
),
30.width,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Approved Check Out".tr().toText11(
color: MyColors.grey67Color,
),
8.height,
"${getScheduleShiftsDetailsList!.aPPROVEDENDTIME}".toText22(color: MyColors.greenColor, isBold: true),
],
),
],
),
25.height,
const Divider(
height: 1,
thickness: 1,
color: MyColors.whiteColor,
),
25.height,
Row(
children: [
Container(
margin: const EdgeInsets.only(right: 30, left: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Late In".tr().toText11(
color: MyColors.grey67Color,
),
8.height,
"${getDayHoursTypeDetailsList[i].lATEINHRS}".toText22(color: MyColors.redColor, isBold: true),
],
),
),
80.width,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Excess".tr().toText11(
color: MyColors.grey67Color,
),
8.height,
"${getDayHoursTypeDetailsList[i].eXCESSHRS}".toText22(color: Colors.black, isBold: true),
],
),
],
),
25.height,
const Divider(
height: 1,
thickness: 1,
color: MyColors.whiteColor,
),
25.height,
Row(
children: [
Container(
margin: const EdgeInsets.only(right: 30, left: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Shortage".tr().toText11(
color: MyColors.grey67Color,
),
8.height,
"${getDayHoursTypeDetailsList[i].sHORTAGEHRS}".toText22(color: Colors.black, isBold: true),
],
),
),
80.width,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Early Out".tr().toText11(
color: MyColors.grey67Color,
),
8.height,
"${getDayHoursTypeDetailsList[i].eARLYOUTHRS}".toText22(color: Colors.black, isBold: true),
],
),
],
),
],
),
),
],
),
],
),
),
),
),
],
);
},
);
},
);
}
List<Meeting> _getDataSource() {
final List<Meeting> meetings = <Meeting>[];
return meetings;
}
static getMonth(int month) {
switch (month) {
case 1:
return "January";
case 2:
return "February";
case 3:
return "March";
case 4:
return "April";
case 5:
return "May";
case 6:
return "June";
case 7:
return "July";
case 8:
return "August";
case 9:
return "September";
case 10:
return "October";
case 11:
return "November";
case 12:
return "December";
}
}
}
class MeetingDataSource extends CalendarDataSource {
MeetingDataSource(List<Meeting> source) {
appointments = source;
}
@override
DateTime getStartTime(int index) {
return _getMeetingData(index).from;
}
@override
DateTime getEndTime(int index) {
return _getMeetingData(index).to;
}
@override
String getSubject(int index) {
return _getMeetingData(index).eventName;
}
@override
Color getColor(int index) {
return _getMeetingData(index).background;
}
@override
bool isAllDay(int index) {
return _getMeetingData(index).isAllDay;
}
Meeting _getMeetingData(int index) {
final dynamic meeting = appointments;
Meeting meetingData;
if (meeting is Meeting) {
meetingData = meeting;
}
return meeting;
}
}
class Meeting {
Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay);
String eventName;
DateTime from;
DateTime to;
Color background;
bool isAllDay;
}