import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:generp/Notifiers/AttendanceNotifier.dart'; import 'package:generp/Notifiers/HomeScreenNotifier.dart'; import 'package:generp/Utils/app_colors.dart'; import 'package:generp/screens/CheckInScreen.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; class AttendanceScreen extends StatefulWidget { const AttendanceScreen({super.key}); @override State createState() => _AttendanceScreenState(); } class _AttendanceScreenState extends State { var att_provider; var homeProvider; @override void initState() { super.initState(); homeProvider = Provider.of(context, listen: false); WidgetsBinding.instance.addPostFrameCallback((_) { att_provider = Provider.of(context, listen: false); att_provider.getAttendanceList(homeProvider, context); att_provider.init(homeProvider, context); }); } @override Widget build(BuildContext context) { return Consumer( builder: (context, attendance, index) { final timeString = attendance.attendanceHistory.firstOrNull?.checkInTime.toString() ?? ""; final match = RegExp( r'^(\d{1,2}:\d{2})(am|pm)$', caseSensitive: false, ).firstMatch(timeString.replaceAll(' ', '').toLowerCase()); final timeString2 = attendance.attendanceHistory.firstOrNull?.checkOutTime.toString() ?? ""; final match2 = RegExp( r'^(\d{1,2}:\d{2})(am|pm)$', caseSensitive: false, ).firstMatch(timeString2.replaceAll(' ', '').toLowerCase()); String formattedTime = match?.group(1) ?? "-"; String period = match?.group(2)?.toUpperCase() ?? ""; String formattedTime2 = match2?.group(1) ?? "-"; String period2 = match2?.group(2)?.toUpperCase() ?? ""; final dateArrayList = attendance.dateArrayList; final penalityArrayList = attendance.penalityArrayList; var selectedIndex = attendance.selectedIndex; // Calculate the custom period: 26th of previous month to 25th of current month final startDate = DateTime(attendance.month.year, attendance.month.month - 1, 26); final endDate = DateTime(attendance.month.year, attendance.month.month, 25); final daysInPeriod = endDate.difference(startDate).inDays + 1; final startingIndex = startDate.weekday % 7; // 0 for Sunday, 1 for Monday, etc. final currentDate = DateTime.now(); // Format the month label (e.g., "Mar - Apr 2025") final prevMonthName = DateFormat('MMM').format(DateTime(attendance.month.year, attendance.month.month - 1)); final currentMonthName = DateFormat('MMM').format(attendance.month); final year = DateFormat('yyyy').format(attendance.month); final monthLabel = prevMonthName == currentMonthName ? '$currentMonthName $year' : '$prevMonthName - $currentMonthName $year'; return Scaffold( backgroundColor: AppColors.scaffold_bg_color, appBar: AppBar(automaticallyImplyLeading: false), body: Container( child: SingleChildScrollView( child: Column( children: [ Container( margin: EdgeInsets.only(top: 15, bottom: 15), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), ), child: Column( children: [ Container( padding: EdgeInsets.only( left: 10, right: 10, top: 15, ), child: Row( children: [ Expanded(child: Text("Check-in")), Expanded(child: Text("Check-out")), ], ), ), Container( padding: EdgeInsets.symmetric( horizontal: 10, vertical: 15, ), margin: EdgeInsets.symmetric( horizontal: 10, vertical: 15, ), decoration: BoxDecoration( color: Color(0xFFFFEFEF), borderRadius: BorderRadius.circular(16), ), child: Row( children: [ Expanded( child: SizedBox( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ RichText( text: TextSpan( children: [ TextSpan( text: "${formattedTime}", style: TextStyle( color: AppColors.semi_black, fontSize: 18, ), ), TextSpan( text: "${period}", style: TextStyle( color: AppColors.semi_black, ), ), ], ), ), Text("Head Office"), ], ), ), ), Expanded( child: SizedBox( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ RichText( text: TextSpan( children: [ TextSpan( text: "${formattedTime2}", style: TextStyle( color: AppColors.semi_black, fontSize: 18, ), ), TextSpan( text: "${period2}", style: TextStyle( color: AppColors.semi_black, ), ), ], ), ), Text("Head Office"), ], ), ), ), ], ), ), ], ), ), Text("Attendance Details"), GridView.builder( itemCount: 4, shrinkWrap: true, physics: NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 10, mainAxisSpacing: 10, childAspectRatio: 20 / 10, ), itemBuilder: (context, index) { final numbers = [ attendance.presentDays, attendance.absentDays, attendance.holidays, attendance.latePenalties ]; final names = [ "Present Days", "Absent Days", "Holidays", "Late Points", ]; return Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(30), ), child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ Text(numbers[index].toString()), Text(names[index]) ], ), ); }, ), ///calendar Padding( padding: const EdgeInsets.fromLTRB(30, 10, 30, 0), child: Container( child: Row( children: [ GestureDetector( onTap: () { attendance.setPreviousMonth(homeProvider, context); }, child: const Icon( Icons.arrow_back_ios, color: Colors.black, size: 30.0, ), ), Spacer(), Text( monthLabel, style: TextStyle( fontWeight: FontWeight.w500, overflow: TextOverflow.ellipsis, color: Colors.black, ), ), Spacer(), GestureDetector( onTap: () { attendance.setNextMonth(homeProvider, context); }, child: const Icon( Icons.arrow_forward_ios, color: Colors.black, size: 30.0, ), ), ], ), ), ), Padding( padding: const EdgeInsets.fromLTRB(8, 10, 8 , 0), child: Container( child: Row( children: [ for (var day in ['S', 'M', 'T', 'W', 'T', 'F', 'S']) Expanded( child: Text( day, textAlign: TextAlign.center, style: TextStyle( overflow: TextOverflow.ellipsis, color: Colors.black, ), ), ), ], ), ), ), Divider( thickness: 0.8, color: Colors.white, ), Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 10), child: Container( height: 280, color: Colors.white, child: GridView.builder( itemCount: daysInPeriod + startingIndex, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 7, crossAxisSpacing: 2, mainAxisSpacing: 1, childAspectRatio: (255 / 245), ), padding: const EdgeInsets.fromLTRB(10, 10, 10, 0), shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemBuilder: (context, index) { if (index < startingIndex) { return SizedBox.shrink(); } final dayIndex = index - startingIndex; final currentDateInPeriod = startDate.add(Duration(days: dayIndex)); final currentDay = currentDateInPeriod.day; final isFutureDate = currentDateInPeriod.isAfter(currentDate); // Find matching date in dateArrayList Map? dateMap; try { dateMap = dateArrayList[dayIndex]; } catch (e) { dateMap = {}; } // Find matching penalty Map? penaltyMap; try { penaltyMap = penalityArrayList[dayIndex]; } catch (e) { penaltyMap = {}; } String? dateColor = dateMap.isNotEmpty ? dateMap.values.first : null; String? penaltyKey = penaltyMap.isNotEmpty ? penaltyMap.keys.first : null; int? datePenalty = penaltyMap.isNotEmpty ? penaltyMap.values.first : 0; // Determine if this is the current day final isCurrentDay = currentDateInPeriod.day == currentDate.day && currentDateInPeriod.month == currentDate.month && currentDateInPeriod.year == currentDate.year; return InkWell( onTap: isFutureDate ? null : () { selectedIndex = index; if (penaltyKey != null) { attendance.dateWiseAttendance( homeProvider, penaltyKey, context); } attendance.selectedDate = currentDay.toString(); }, child: Card( elevation: 0, child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( datePenalty != 0 ? "($datePenalty)" : "", style: TextStyle( fontWeight: FontWeight.w400, color: Colors.black, ), ), ], ), Center( child: Container( decoration: BoxDecoration( shape: BoxShape.circle, color: isFutureDate ? Colors.transparent : (isCurrentDay || (selectedIndex == index)) ? Colors.blueAccent : dateColor == 'g' ? Colors.green : dateColor == 'r' ? Colors.red : dateColor == 'b' ? Colors.blueAccent : dateColor == 'br' ? Colors.brown : dateColor == 'y' ? Colors.yellow : Colors.transparent, ), child: Center( child: Text( currentDay.toString(), style: TextStyle( fontSize: 14, fontWeight: FontWeight.w400, color: (isCurrentDay || (selectedIndex == index)) ? Colors.white : Colors.black, ), ), ), ), ), ], ), ), ); }, ), ), ), SizedBox(height: 60), ], ), ), ), floatingActionButton: Align( alignment: Alignment.bottomCenter, child: InkWell( onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context)=>CheckInOutScreen( getAttendanceStatus: attendance.attendanceStatus, ))); var f = FocusScope.of(context); if (!f.hasPrimaryFocus) { f.unfocus(); } }, child: Container( alignment: Alignment.bottomCenter, height: 45, width: MediaQuery.of(context).size.width, decoration: BoxDecoration( color: AppColors.app_blue, borderRadius: BorderRadius.circular(30.0), ), child: Center( child: Text( attendance.attendanceStatus == 0 ? "Check In" : "Check Out", textAlign: TextAlign.center, style: TextStyle(color: Colors.white), ), ), ), ), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, ); }, ); } }