Commit 2a8fa440 authored by Sai Srinivas's avatar Sai Srinivas
Browse files

AttendanceScreen and hrm color and responsive

parents 96031396 9e243e0c
......@@ -42,8 +42,8 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "in.webgrid.generp"
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
minSdk = 23
targetSdk = 36
versionCode = flutter.versionCode
versionName = flutter.versionName
}
......
......@@ -949,6 +949,11 @@ class Addnewleadsandprospectsprovider extends ChangeNotifier {
nameError = "Please Enter Name";
isValid = false;
}
if(nameError == "Name already exists"){
isValid = false;
}
if (customerMailIdController.text.trim().isNotEmpty &&
!RegExp(r'\S+@\S+\.\S+').hasMatch(customerMailIdController.text)) {
mailIdError = "Please enter a proper Email ID";
......@@ -963,6 +968,9 @@ class Addnewleadsandprospectsprovider extends ChangeNotifier {
isValid = false;
}
}
if ( mobileError == "Mobile number already exists"){
isValid = false;
}
// if(designationController.text.trim().isEmpty){
// designationError = "Please enter Designation";
......@@ -973,6 +981,11 @@ class Addnewleadsandprospectsprovider extends ChangeNotifier {
return isValid;
}
bool validateStep2() {
bool isValid = true;
if (alternateMobileController.text.trim().isNotEmpty &&
......
......@@ -52,6 +52,38 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
_connectivity.disposeStream();
}
// Responsive text size function
double getResponsiveTextSize(BuildContext context, double baseSize) {
final double scale = MediaQuery.of(context).textScaleFactor;
final double width = MediaQuery.of(context).size.width;
if (width < 360) { // Small phones
return baseSize * 0.9;
} else if (width < 400) { // Medium phones
return baseSize;
} else { // Large phones
return baseSize * 1.1;
}
}
// Responsive padding function
double getResponsivePadding(BuildContext context) {
final double width = MediaQuery.of(context).size.width;
return width * 0.04; // 4% of screen width
}
// Responsive height function
double getResponsiveHeight(BuildContext context, double baseHeight) {
final double height = MediaQuery.of(context).size.height;
if (height < 700) { // Small height devices
return baseHeight * 0.8;
} else if (height < 800) { // Medium height devices
return baseHeight;
} else { // Large height devices
return baseHeight * 1.1;
}
}
@override
Widget build(BuildContext context) {
switch (_source.keys.toList()[0]) {
......@@ -67,583 +99,592 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
}
return (connection == 'Online')
? Platform.isAndroid
? WillPopScope(
onWillPop: () => onBackPressed(context),
child: SafeArea(
top: false,
bottom: true,
child: _scaffold(context),
),
)
: _scaffold(context)
? WillPopScope(
onWillPop: () => onBackPressed(context),
child: SafeArea(
top: false,
bottom: true,
child: _scaffold(context),
),
)
: _scaffold(context)
: NoNetwork(context);
}
Widget _scaffold(BuildContext context) {
return Consumer<AttendanceNotifier>(
builder: (context, attendance, index) {
final timeString =
attendance.attendanceHistory.firstOrNull?['check_in_time']
.toString() ??
"";
final match = RegExp(
r'^(\d{1,2}:\d{2})(am|pm)$',
caseSensitive: false,
).firstMatch(timeString.replaceAll(' ', '').toLowerCase());
final timeString2 =
attendance.attendanceHistory.firstOrNull?['check_out_time']
.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';
final monthLabel = '$currentMonthName $year';
return RefreshIndicator.adaptive(
color: AppColors.app_blue,
onRefresh: () async {
await Future.delayed(const Duration(milliseconds: 600));
attendance.getAttendanceList(context);
attendance.init(context);
attendance.loadAttendanceDetails(context);
},
child: Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: AppColors.scaffold_bg_color,
appBar: appbarNew(context, "Attendance", 0xFFFFFFFF),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(20),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(
left: 15,
right: 10,
top: 15,
),
child: Row(
children: List.generate(2, (j) {
final heads = ["Check-in", "Check-out"];
return Expanded(
child: Text(
heads[j],
style: TextStyle(
color: AppColors.grey_thick,
fontSize: 14,
fontFamily: "JakartaMedium",
),
),
);
}),
return LayoutBuilder(
builder: (context, constraints) {
final bool isSmallScreen = constraints.maxWidth < 360;
final bool isLargeScreen = constraints.maxWidth > 400;
return Consumer<AttendanceNotifier>(
builder: (context, attendance, index) {
final timeString =
attendance.attendanceHistory.firstOrNull?['check_in_time']
.toString() ??
"";
final match = RegExp(
r'^(\d{1,2}:\d{2})(am|pm)$',
caseSensitive: false,
).firstMatch(timeString.replaceAll(' ', '').toLowerCase());
final timeString2 =
attendance.attendanceHistory.firstOrNull?['check_out_time']
.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 = '$currentMonthName $year';
return RefreshIndicator.adaptive(
color: AppColors.app_blue,
onRefresh: () async {
await Future.delayed(const Duration(milliseconds: 600));
attendance.getAttendanceList(context);
attendance.init(context);
attendance.loadAttendanceDetails(context);
},
child: Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: AppColors.scaffold_bg_color,
appBar: appbarNew(context, "Attendance", 0xFFFFFFFF),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(20),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(
left: getResponsivePadding(context),
right: getResponsivePadding(context),
top: 15,
),
child: Row(
children: List.generate(2, (j) {
final heads = ["Check-in", "Check-out"];
return Expanded(
child: Text(
heads[j],
style: TextStyle(
color: AppColors.grey_thick,
fontSize: getResponsiveTextSize(context, 14),
fontFamily: "JakartaMedium",
),
),
);
}),
),
),
SizedBox(
child: Row(
children: List.generate(2, (iii) {
final times = [formattedTime, formattedTime2];
final periods = [period, period2];
final locations = [
attendance.attendanceHistory.isNotEmpty
? attendance
.attendanceHistory
.first['check_in_location']
.toString() ??
Container(
padding: EdgeInsets.symmetric(horizontal: getResponsivePadding(context)-6),
child: Row(
children: List.generate(2, (iii) {
final times = [formattedTime, formattedTime2];
final periods = [period, period2];
final locations = [
attendance.attendanceHistory.isNotEmpty
? attendance
.attendanceHistory
.first['check_in_location']
.toString() ??
"-"
: "-",
attendance.attendanceHistory.isNotEmpty
? attendance
.attendanceHistory
.first['check_out_location']
.toString() ??
: "-",
attendance.attendanceHistory.isNotEmpty
? attendance
.attendanceHistory
.first['check_out_location']
.toString() ??
"-"
: "-",
];
return Expanded(
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 15,
),
margin: EdgeInsets.symmetric(
horizontal: 5,
vertical: 5,
),
decoration: BoxDecoration(
color: Color(0xFFF3EDFF),
borderRadius: BorderRadius.circular(20),
),
child: Column(
crossAxisAlignment:
: "-",
];
return Expanded(
child: Container(
padding: EdgeInsets.symmetric(
horizontal: isSmallScreen ? 8 : 10,
vertical: isSmallScreen ? 11 : 16,
),
margin: EdgeInsets.symmetric(
horizontal: isSmallScreen ? 3 : 5,
vertical: isSmallScreen ? 3 : 5,
),
decoration: BoxDecoration(
color: Color(0xFFE6F6FF),
borderRadius: BorderRadius.circular(20),
),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
RichText(
text: TextSpan(
children: [
TextSpan(
text: times[iii],
style: TextStyle(
color:
children: [
RichText(
text: TextSpan(
children: [
TextSpan(
text: times[iii],
style: TextStyle(
color:
times[iii] != "-"
? Color(0xFF1286C7)
: Color(0xFFED3424),
fontFamily: "JakartaRegular",
fontSize: 20,
),
),
TextSpan(
text: periods[iii],
style: TextStyle(
color:
: Color(0xFF1286C7),
fontFamily: "JakartaRegular",
fontSize: getResponsiveTextSize(context, 20),
),
),
TextSpan(
text: periods[iii],
style: TextStyle(
color:
periods[iii] != "-"
? Color(0xFF1286C7)
: Color(0xFFED3424),
fontFamily: "JakartaRegular",
fontSize: 14,
),
fontFamily: "JakartaRegular",
fontSize: getResponsiveTextSize(context, 14),
),
),
],
),
],
),
),
SizedBox(height: 10),
Text(
locations[iii],
style: TextStyle(
color: AppColors.semi_black,
fontSize: 12,
),
),
SizedBox(height: isSmallScreen ? 12 : 16),
Text(
locations[iii],
style: TextStyle(
color: AppColors.semi_black,
fontSize: getResponsiveTextSize(context, 12),
),
),
],
),
],
),
),
);
}),
),
),
),
);
}),
),
),
Container(
padding: EdgeInsets.only(left: 10, top: 10),
child: Text(
"Attendance Details",
style: TextStyle(
fontFamily: "JakartaMedium",
fontSize: 14,
color: Color(0xFF818181),
Container(
padding: EdgeInsets.only(
left: getResponsivePadding(context),
top: 10
),
child: Text(
"Attendance Details",
style: TextStyle(
fontFamily: "JakartaMedium",
fontSize: getResponsiveTextSize(context, 14),
color: Color(0xFF818181),
),
),
),
),
),
Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
Container(
padding: EdgeInsets.symmetric(
horizontal: getResponsivePadding(context),
vertical: 10,
),
child: GridView.builder(
itemCount: 4,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate:
child: GridView.builder(
itemCount: 4,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 20 / 10,
crossAxisSpacing: isSmallScreen ? 8 : 10,
mainAxisSpacing: isSmallScreen ? 8 : 10,
childAspectRatio: isSmallScreen ? 18/9 : 20/10,
),
itemBuilder: (context, index) {
final numbers = [
attendance.presentDays,
attendance.absentDays,
attendance.holidays,
attendance.latePenalties,
];
final names = [
"Present \nDays",
"Absent \nDays",
"Holidays",
"Late \nPoints",
];
final colors = [
0xFFE7FFE5,
0xFFFFEFEF,
0xFFF3EDFF,
0xFFFFF6F0,
];
final textcolors = [
0xFF0D9C00,
0xFFFF0000,
0xFF493272,
0xFF91481B,
];
final assetNames = [
"assets/svg/attendance/present_ic.svg",
"assets/svg/attendance/absent_ic.svg",
"assets/svg/attendance/holidays_ic.svg",
"assets/svg/attendance/penalty_ic.svg",
];
itemBuilder: (context, index) {
final numbers = [
attendance.presentDays,
attendance.absentDays,
attendance.holidays,
attendance.latePenalties,
];
final names = [
"Present \nDays",
"Absent \nDays",
"Holidays",
"Late \nPoints",
];
final colors = [
0xFFE7FFE5,
0xFFFFEFEF,
0xFFF3EDFF,
0xFFFFF6F0,
];
final textcolors = [
0xFF0D9C00,
0xFFFF0000,
0xFF493272,
0xFF91481B,
];
final assetNames = [
"assets/svg/attendance/present_ic.svg",
"assets/svg/attendance/absent_ic.svg",
"assets/svg/attendance/holidays_ic.svg",
"assets/svg/attendance/penalty_ic.svg",
];
return Container(
padding: EdgeInsets.symmetric(horizontal: 13),
decoration: BoxDecoration(
color: Color(colors[index]),
borderRadius: BorderRadius.circular(20),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
numbers[index].toString(),
style: TextStyle(
fontSize: 20,
fontFamily: "JakartaMedium",
color: Color(textcolors[index]),
),
return Container(
padding: EdgeInsets.symmetric(
horizontal: isSmallScreen ? 10 : 13
),
Row(
decoration: BoxDecoration(
color: Color(colors[index]),
borderRadius: BorderRadius.circular(20),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 4,
child: Text(
names[index],
style: TextStyle(
fontSize: 14,
fontFamily: "JakartaRegular",
color: AppColors.semi_black,
),
Text(
numbers[index].toString(),
style: TextStyle(
fontSize: getResponsiveTextSize(context, 20),
fontFamily: "JakartaMedium",
color: Color(textcolors[index]),
),
),
Expanded(
flex: 1,
child: SvgPicture.asset(
assetNames[index],
),
Row(
children: [
Expanded(
flex: 4,
child: Text(
names[index],
style: TextStyle(
fontSize: getResponsiveTextSize(context, 14),
fontFamily: "JakartaRegular",
color: AppColors.semi_black,
),
),
),
Expanded(
flex: 1,
child: SvgPicture.asset(
assetNames[index],
width: isSmallScreen ? 20 : 38,
height: isSmallScreen ? 20 : 38,
),
),
],
),
],
),
],
),
);
},
),
);
},
),
),
],
),
],
),
),
SizedBox(height: 15),
///calendar
Container(
// padding: EdgeInsets.symmetric(horizontal: 10,vertical: 5),
margin: EdgeInsets.symmetric(horizontal: 15, vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white,
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(30, 10, 30, 0),
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
child: Row(
children: [
GestureDetector(
onTap: () {
attendance.setPreviousMonth(context);
},
child: Padding(
padding: const EdgeInsets.all(4.0),
child: SvgPicture.asset(
"assets/svg/crm/calendar_left.svg",
),
SizedBox(height: 15),
///calendar
Container(
margin: EdgeInsets.symmetric(
horizontal: getResponsivePadding(context),
vertical: 10
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white,
),
child: Column(
children: [
Padding(
padding: EdgeInsets.fromLTRB(
isSmallScreen ? 20 : 30,
10,
isSmallScreen ? 20 : 30,
0
),
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
child: Row(
children: [
GestureDetector(
onTap: () {
attendance.setPreviousMonth(context);
},
child: Padding(
padding: const EdgeInsets.all(4.0),
child: SvgPicture.asset(
"assets/svg/crm/calendar_left.svg",
width: isSmallScreen ? 18 : 24,
height: isSmallScreen ? 18 : 24,
),
),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 5.0,
),
child: Text(
monthLabel,
style: TextStyle(
overflow: TextOverflow.ellipsis,
fontFamily: "JakartaMedium",
color: Color(0xFF2D2D2D),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 5.0,
),
child: Text(
monthLabel,
style: TextStyle(
overflow: TextOverflow.ellipsis,
fontFamily: "JakartaMedium",
fontSize: getResponsiveTextSize(context, 14.5),
color: Color(0xFF2D2D2D),
),
),
),
),
),
GestureDetector(
onTap: () {
attendance.setNextMonth(context);
},
child: Padding(
padding: const EdgeInsets.all(4.0),
child: SvgPicture.asset(
"assets/svg/crm/calendar_right.svg",
GestureDetector(
onTap: () {
attendance.setNextMonth(context);
},
child: Padding(
padding: const EdgeInsets.all(4.0),
child: SvgPicture.asset(
"assets/svg/crm/calendar_right.svg",
width: isSmallScreen ? 18 : 24,
height: isSmallScreen ? 18 : 24,
),
),
),
),
],
),
],
),
),
),
InkResponse(
onTap: () {
_showInfoBottomSheet(context);
},
child: SizedBox(
width: 20,
height: 20,
child: SvgPicture.asset(
"assets/svg/ic_info_new.svg",
width: 20,
height: 20,
InkResponse(
onTap: () {
_showInfoBottomSheet(context);
},
child: SizedBox(
width: isSmallScreen ? 18 : 20,
height: isSmallScreen ? 18 : 20,
child: SvgPicture.asset(
"assets/svg/ic_info_new.svg",
width: isSmallScreen ? 18 : 20,
height: isSmallScreen ? 18 : 20,
),
),
),
),
],
),
],
),
),
),
),
SizedBox(height: 5),
Padding(
padding: const EdgeInsets.fromLTRB(8, 10, 8, 0),
child: Container(
child: Row(
children: [
for (
var i = 0;
i <
[
'S',
'M',
'T',
'W',
'T',
'F',
'S',
].length;
i++
)
Expanded(
child: Text(
['S', 'M', 'T', 'W', 'T', 'F', 'S'][i],
textAlign: TextAlign.center,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color:
SizedBox(height: 5),
Padding(
padding: const EdgeInsets.fromLTRB(4, 10, 2, 0),
child: Container(
child: Row(
children: [
for (
var i = 0;
i <
[
'S',
'M',
'T',
'W',
'T',
'F',
'S',
].length;
i++
)
Expanded(
child: Text(
['S', 'M', 'T', 'W', 'T', 'F', 'S'][i],
textAlign: TextAlign.center,
style: TextStyle(
fontSize: getResponsiveTextSize(context, 15),
overflow: TextOverflow.ellipsis,
color:
i == 0
? Color(0xFFFF0000)
: AppColors.semi_black,
),
),
),
),
),
],
],
),
),
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Container(
child: GridView.builder(
itemCount: daysInPeriod + startingIndex,
gridDelegate:
SizedBox(height: 3,),
Padding(
padding: const EdgeInsets.fromLTRB(4, 0, 2, 10),
child: Container(
child: GridView.builder(
itemCount: daysInPeriod + startingIndex,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 7,
crossAxisSpacing: 2,
mainAxisSpacing: 1,
childAspectRatio: (255 / 245),
childAspectRatio: isSmallScreen ? 1.0 : (255 / 245),
),
padding: const EdgeInsets.fromLTRB(0, 0, 0, 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<String, dynamic>? dateMap;
try {
dateMap = dateArrayList[dayIndex];
} catch (e) {
dateMap = {};
}
// Find matching penalty
Map<String, dynamic>? penaltyMap;
try {
penaltyMap = penalityArrayList[dayIndex];
} catch (e) {
penaltyMap = {};
}
String? dateColor =
padding: const EdgeInsets.fromLTRB(0, 0, 0, 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<String, dynamic>? dateMap;
try {
dateMap = dateArrayList[dayIndex];
} catch (e) {
dateMap = {};
}
// Find matching penalty
Map<String, dynamic>? penaltyMap;
try {
penaltyMap = penalityArrayList[dayIndex];
} catch (e) {
penaltyMap = {};
}
String? dateColor =
dateMap.isNotEmpty
? dateMap.values.first
: null;
String? penaltyKey =
String? penaltyKey =
penaltyMap.isNotEmpty
? penaltyMap.keys.first
: null;
int? datePenalty =
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:
// 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(
penaltyKey,
context,
);
}
attendance.selectedDate =
currentDay.toString();
_showAttDetailsBottomSheet(context);
},
child: Card(
elevation: 0,
child: Column(
children: [
// Row(
// mainAxisAlignment:
// MainAxisAlignment.center,
// children: [
// Text(
// "($datePenalty)",
// style: TextStyle(
// fontWeight: FontWeight.w400,
// color: Colors.black,
// fontSize: 5
// ),
// ),
// ],
// ),
Center(
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color:
selectedIndex = index;
if (penaltyKey != null) {
attendance.dateWiseAttendance(
penaltyKey,
context,
);
}
attendance.selectedDate =
currentDay.toString();
_showAttDetailsBottomSheet(context);
},
child: Card(
elevation: 0,
child: Column(
children: [
Center(
child: Container(
padding : EdgeInsets.all(2),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color:
(isCurrentDay ||
(selectedIndex ==
index))
(selectedIndex ==
index))
? Color(0xFF1487C9)
: Colors.transparent,
),
color:
),
color:
isFutureDate
? Colors.transparent
: (isCurrentDay ||
(selectedIndex ==
index))
(selectedIndex ==
index))
? Color(0xFFFFFFFF)
: dateColor == 'g'
? Color(
0xFFE7FFE5,
).withAlpha(50)
0xFFE8FFE6,
)
: dateColor == 'r'
? Color(
0xFFFF0000,
).withAlpha(50)
0xFFFF0000,
).withAlpha(50)
: dateColor == 'b'
? Color(
0xFF493272,
).withAlpha(50)
0xFF493272,
).withAlpha(50)
: dateColor == 'br'
? Color(0xFFFFE8D0)
: dateColor == 'y'
? Color(0xFFFFF9B2)
: Colors.transparent,
),
child: Center(
child: Text(
currentDay.toString(),
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color:
),
child: Center(
child: Text(
currentDay.toString(),
style: TextStyle(
fontSize: getResponsiveTextSize(context, 13),
fontWeight: FontWeight.w400,
color:
isFutureDate
? AppColors.semi_black
: (isCurrentDay ||
(selectedIndex ==
index))
(selectedIndex ==
index))
? Color(0xFF2D2D2D)
: dateColor == 'g'
? Color(0xFF0D9C00)
......@@ -656,88 +697,92 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
: dateColor == 'y'
? Color(0xFF605C00)
: Colors.transparent,
),
),
),
),
),
),
],
),
],
),
),
);
},
),
);
},
),
),
),
),
],
),
],
),
),
SizedBox(height: 25),
],
),
SizedBox(height: 25),
],
),
),
bottomNavigationBar:
),
bottomNavigationBar:
attendance.attendanceStatus == 0 ||
attendance.attendanceStatus == 1
attendance.attendanceStatus == 1
? Container(
height: 75,
decoration: BoxDecoration(color: Colors.white),
padding: EdgeInsets.symmetric(vertical: 10),
child: Align(
alignment: Alignment.center,
child: InkWell(
onTap: () async {
var res = await Navigator.push(
context,
MaterialPageRoute(
builder:
(context) => CheckInOutScreen(
getAttendanceStatus:
attendance.attendanceStatus,
),
),
);
if (res == true) {
attendance.getAttendanceList(context);
attendance.init(context);
attendance.loadAttendanceDetails(context);
}
var f = FocusScope.of(context);
if (!f.hasPrimaryFocus) {
f.unfocus();
}
},
child: Container(
alignment: Alignment.bottomCenter,
height: 45,
margin: EdgeInsets.symmetric(horizontal: 10),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: AppColors.app_blue,
borderRadius: BorderRadius.circular(15.0),
height: getResponsiveHeight(context, 75),
decoration: BoxDecoration(color: Colors.white),
padding: EdgeInsets.symmetric(vertical: 10),
child: Align(
alignment: Alignment.center,
child: InkWell(
onTap: () async {
var res = await Navigator.push(
context,
MaterialPageRoute(
builder:
(context) => CheckInOutScreen(
getAttendanceStatus:
attendance.attendanceStatus,
),
child: Center(
child: Text(
attendance.attendanceStatus == 0
? "Check In"
: "Check Out",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: Colors.white,
fontFamily: "JakartaMedium",
),
),
),
);
if (res == true) {
attendance.getAttendanceList(context);
attendance.init(context);
attendance.loadAttendanceDetails(context);
}
var f = FocusScope.of(context);
if (!f.hasPrimaryFocus) {
f.unfocus();
}
},
child: Container(
alignment: Alignment.bottomCenter,
height: 45,
margin: EdgeInsets.symmetric(
horizontal: getResponsivePadding(context)
),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: AppColors.app_blue,
borderRadius: BorderRadius.circular(15.0),
),
child: Center(
child: Text(
attendance.attendanceStatus == 0
? "Check In"
: "Check Out",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: getResponsiveTextSize(context, 16),
color: Colors.white,
fontFamily: "JakartaMedium",
),
),
),
),
)
),
),
)
: SizedBox(height: 0),
floatingActionButtonLocation:
floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat,
),
),
);
},
);
},
);
......@@ -779,19 +824,19 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
style: TextStyle(
color: AppColors.app_blue,
fontFamily: "JakartaSemiBold",
fontSize: 16,
fontSize: getResponsiveTextSize(context, 16),
),
),
SizedBox(height: 15),
GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 0,
mainAxisExtent: 40,
mainAxisSpacing: 10,
childAspectRatio: 6 / 1,
),
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 0,
mainAxisExtent: 40,
mainAxisSpacing: 10,
childAspectRatio: 6 / 1,
),
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 5,
......@@ -825,8 +870,8 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
Expanded(
flex: 1,
child: Container(
width: 18,
height: 18,
width: 25,
height: 25,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: colors[index],
......@@ -836,7 +881,7 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
textSubs[index],
style: TextStyle(
color: textColors[index],
fontSize: 10,
fontSize: getResponsiveTextSize(context, 12),
),
),
),
......@@ -850,7 +895,7 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 14,
fontSize: getResponsiveTextSize(context, 14),
color: Colors.black,
),
),
......@@ -878,7 +923,6 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
isDismissible: true,
isScrollControlled: true,
showDragHandle: true,
enableDrag: true,
context: context,
builder: (context) {
......@@ -897,7 +941,6 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
......@@ -912,14 +955,14 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
style: TextStyle(
color: AppColors.app_blue,
fontFamily: "JakartaSemiBold",
fontSize: 16,
fontSize: getResponsiveTextSize(context, 16),
),
),
Text(
provider.date,
style: TextStyle(
color: Color(0xFF818181),
fontSize: 12,
fontSize: getResponsiveTextSize(context, 12),
),
),
],
......@@ -940,12 +983,14 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
"Late Points ",
style: TextStyle(
fontFamily: "JakartaMedium",
fontSize: getResponsiveTextSize(context, 14),
),
),
Text(
provider.penalties,
style: TextStyle(
color: Color(0xFF91481B),
fontSize: getResponsiveTextSize(context, 14),
),
),
],
......@@ -954,13 +999,12 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
],
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 5),
padding: EdgeInsets.symmetric(horizontal: 5, vertical: 15),
child: Divider(
color: Color(0xFFD7D7D7),
thickness: 0.5,
),
),
SizedBox(height: 15),
...List.generate(4, (j) {
final values = [
"Check-in Time",
......@@ -974,31 +1018,43 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
(provider.outtime),
(provider.outlocation),
];
return SizedBox(
height: 35,
return Container(
margin: EdgeInsets.only(bottom: 12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 2,
child: Text(
values[j],
style: TextStyle(
fontFamily: "JakartaMedium",
color: AppColors.semi_black,
fontSize: getResponsiveTextSize(context, 14),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
SizedBox(width: 10),
Expanded(
flex: 3,
child: Text(
subvalues[j],
subvalues[j].isEmpty ? "-" : subvalues[j],
style: TextStyle(
color: Color(0xFF818181),
fontSize: getResponsiveTextSize(context, 14),
),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
),
],
),
);
}),
SizedBox(height: 10),
],
),
),
......@@ -1011,4 +1067,4 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
},
);
}
}
}
\ No newline at end of file
......@@ -1440,7 +1440,6 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
null,
TextInputAction.done,
),
errorWidget(context, provider.addressError),
],
),
......@@ -1620,4 +1619,33 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
},
);
}
void showCustomSnackBar(BuildContext context, String message) {
final snackBar = SnackBar(
behavior: SnackBarBehavior.floating,
backgroundColor: Colors.black87,
elevation: 6,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
content: Row(
children: [
Icon(Icons.info_outline, color: Colors.white),
SizedBox(width: 12),
Expanded(
child: Text(
message,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
),
],
),
duration: Duration(seconds: 3),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}
......@@ -30,11 +30,43 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
"Casual Leave List"
];
// Responsive text size function
double getResponsiveTextSize(BuildContext context, double baseSize) {
final double scale = MediaQuery.of(context).textScaleFactor;
final double width = MediaQuery.of(context).size.width;
if (width < 360) { // Small phones
return baseSize * 0.85;
} else if (width < 400) { // Medium phones
return baseSize;
} else { // Large phones
return baseSize * 1.1;
}
}
// Responsive padding function
double getResponsivePadding(BuildContext context) {
final double width = MediaQuery.of(context).size.width;
return width * 0.04; // 4% of screen width
}
// Responsive height function
double getResponsiveHeight(BuildContext context, double baseHeight) {
final double height = MediaQuery.of(context).size.height;
if (height < 700) { // Small height devices
return baseHeight * 0.85;
} else if (height < 800) { // Medium height devices
return baseHeight;
} else { // Large height devices
return baseHeight * 1.15;
}
}
@override
void initState() {
super.initState();
Future.microtask(
() => Provider.of<HrmAccessiblePagesProvider>(
() => Provider.of<HrmAccessiblePagesProvider>(
context,
listen: false,
).fetchAccessiblePages(context),
......@@ -43,6 +75,9 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
@override
Widget build(BuildContext context) {
final bool isSmallScreen = MediaQuery.of(context).size.width < 360;
final bool isLargeScreen = MediaQuery.of(context).size.width > 400;
return SafeArea(
top: false,
child: Scaffold(
......@@ -55,14 +90,14 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
onTap: () => Navigator.pop(context, true),
child: SvgPicture.asset(
"assets/svg/appbar_back_button.svg",
height: 25,
height: isSmallScreen ? 22 : 25,
),
),
const SizedBox(width: 10),
SizedBox(width: isSmallScreen ? 8 : 10),
Text(
"HRM",
style: TextStyle(
fontSize: 18,
fontSize: getResponsiveTextSize(context, 18),
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w600,
color: AppColors.semi_black,
......@@ -80,13 +115,16 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
children: [
Container(
width: double.infinity,
height: 490,
height: getResponsiveHeight(context, 490),
color: const Color(0xffF6F6F8),
),
Container(
width: double.infinity,
height: 490,
padding: const EdgeInsets.only(top: 1, bottom: 30),
height: getResponsiveHeight(context, 490),
padding: EdgeInsets.only(
top: 1,
bottom: getResponsiveHeight(context, 30)
),
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
......@@ -101,10 +139,13 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
),
Container(
width: double.infinity,
padding: const EdgeInsets.only(top: 1, bottom: 30),
padding: EdgeInsets.only(
top: 1,
bottom: getResponsiveHeight(context, 30)
),
child: Image.asset(
"assets/images/vector.png",
height: 230,
height: getResponsiveHeight(context, 230),
width: double.infinity,
fit: BoxFit.fitWidth,
),
......@@ -116,26 +157,27 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
/// Top Illustration & Button
Container(
width: double.infinity,
padding: const EdgeInsets.only(top: 60, bottom: 30),
padding: EdgeInsets.only(
top: getResponsiveHeight(context, 60),
bottom: getResponsiveHeight(context, 30)
),
child: Column(
children: [
SvgPicture.asset(
"assets/images/capa.svg",
height: 146,
width: 400,
height: getResponsiveHeight(context, 146),
width: MediaQuery.of(context).size.width * 0.9,
),
const SizedBox(height: 32),
SizedBox(height: getResponsiveHeight(context, 32)),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 8,
padding: EdgeInsets.symmetric(
horizontal: isSmallScreen ? 16 : 20,
vertical: isSmallScreen ? 6 : 8,
),
decoration: BoxDecoration(
border: Border.all(
color: const Color(
0xFF1487C9,
), // border color
width: 1.2, // thickness of the border
color: const Color(0xFF1487C9),
width: 1.2,
),
color: const Color(0xffEDF8FF),
borderRadius: BorderRadius.circular(30),
......@@ -154,23 +196,28 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
children: [
SvgPicture.asset(
"assets/svg/hrm/groupIc.svg",
height: 29,
width: 29,
height: isSmallScreen ? 25 : 29,
width: isSmallScreen ? 25 : 29,
fit: BoxFit.contain,
),
const SizedBox(width: 7),
const Text(
"Organization Structure",
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
fontStyle: FontStyle.normal,
fontFamily: "Plus Jakarta Sans",
SizedBox(width: isSmallScreen ? 5 : 7),
Flexible(
child: Text(
"Organization Structure",
style: TextStyle(
fontSize: getResponsiveTextSize(context, 15),
fontWeight: FontWeight.w500,
fontStyle: FontStyle.normal,
fontFamily: "Plus Jakarta Sans",
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
const Icon(
Icon(
Icons.chevron_right,
color: Colors.black54,
size: isSmallScreen ? 18 : 20,
),
],
),
......@@ -183,9 +230,13 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
/// Grid Section
LayoutBuilder(
builder: (context, constraints) {
final screenWidth = constraints.maxWidth;
final crossAxisCount = (screenWidth / 180).floor().clamp(2, 4);
final childAspectRatio = screenWidth < 360 ? 1.5 : 1.7;
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8,
padding: EdgeInsets.symmetric(
horizontal: getResponsivePadding(context),
vertical: 10,
),
child: Consumer<HrmAccessiblePagesProvider>(
......@@ -197,38 +248,40 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
}
if (provider.errorMessage != null) {
return Center(
child: Text(provider.errorMessage!),
child: Text(
provider.errorMessage!,
style: TextStyle(
fontSize: getResponsiveTextSize(context, 14),
),
),
);
}
final pages =
(provider.response?.pagesAccessible ?? [])
.where(
(page) => allowedPages.contains(
page.pageName,
),
)
.toList();
(provider.response?.pagesAccessible ?? [])
.where(
(page) => allowedPages.contains(
page.pageName,
),
).toList();
return GridView.builder(
itemCount: pages.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: (constraints.maxWidth /
180)
.floor()
.clamp(2, 6),
crossAxisSpacing: 1,
mainAxisSpacing: 2,
childAspectRatio: 1.8,
),
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
crossAxisSpacing: isSmallScreen ? 2 : 4,
mainAxisSpacing: isSmallScreen ? 2 : 4,
childAspectRatio: childAspectRatio,
),
itemBuilder: (context, index) {
final page = pages[index];
return _buildTile(
label: page.pageName ?? "",//in page number there is 6 items comming from serever it showing only four
context: context,
label: page.pageName ?? "",
subtitle: _getSubtitle(
page.pageName ?? "",
),
......@@ -236,10 +289,10 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
txtColor: const Color(0xff1487C9),
onTap:
() => _handleNavigation(
context,
page.pageName ?? "",
page.mode ?? "",
),
context,
page.pageName ?? "",
page.mode ?? "",
),
);
},
);
......@@ -249,10 +302,7 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
},
),
////////////
SizedBox(height: 40,)
SizedBox(height: getResponsiveHeight(context, 40)),
],
),
],
......@@ -266,12 +316,15 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
/// Card builder
Widget _buildTile({
required BuildContext context,
required String label,
required String subtitle,
required String assetIcon,
required Color txtColor,
VoidCallback? onTap,
}) {
final bool isSmallScreen = MediaQuery.of(context).size.width < 360;
return LayoutBuilder(
builder: (context, constraints) {
return InkWell(
......@@ -279,18 +332,28 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
borderRadius: BorderRadius.circular(14),
child: Container(
padding: EdgeInsets.symmetric(
vertical: constraints.maxHeight * 0.05,
horizontal: constraints.maxWidth * 0.05,
vertical: constraints.maxHeight * 0.08,
horizontal: constraints.maxWidth * 0.06,
),
margin: EdgeInsets.symmetric(
vertical: isSmallScreen ? 4 : 7,
horizontal: isSmallScreen ? 3 : 5
),
margin: const EdgeInsets.symmetric(vertical: 7, horizontal: 5),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(14),
// boxShadow: [
// BoxShadow(
// color: Colors.black12,
// blurRadius: 4,
// offset: Offset(0, 2),
// ),
// ],
),
child: Row(
children: [
Expanded(
flex: 2,
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
......@@ -299,25 +362,29 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
child: Text(
label,
style: TextStyle(
fontSize: 14,
fontSize: getResponsiveTextSize(context, 14),
color: AppColors.app_blue,
fontFamily: "JakartaMedium",
height: 1.2,
),
softWrap: true,
overflow: TextOverflow.visible,
overflow: TextOverflow.ellipsis,
maxLines: isSmallScreen ? 2 : 3,
),
),
const SizedBox(height: 4),
SizedBox(height: isSmallScreen ? 2 : 6),
Flexible(
child: Text(
subtitle,
style: TextStyle(
fontSize: 12,
fontSize: getResponsiveTextSize(context, 12),
color: AppColors.grey_semi,
fontFamily: "JakartaMedium",
height: 1,
),
softWrap: true,
overflow: TextOverflow.visible,
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
),
],
......@@ -326,8 +393,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
Expanded(
flex: 1,
child: Container(
height: constraints.maxHeight * 0.39,
width: constraints.maxHeight * 0.39,
height: constraints.maxHeight * 0.45,
width: constraints.maxHeight * 0.45,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: const Color(0xFFEDF8FF),
......@@ -335,8 +402,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
child: Center(
child: SvgPicture.asset(
assetIcon,
height: constraints.maxHeight * 0.19,
width: constraints.maxHeight * 0.19,
height: constraints.maxHeight * 0.22,
width: constraints.maxHeight * 0.22,
),
),
),
......@@ -361,9 +428,9 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
case "Tour Bill List":
return "Submit and manage claims";
case "Team Leave Request Approval":
return "";
return "Approve & Reject";
case "Team Attendance Approval":
return "";
return "Team Attendance Request";
case "Advance List":
return "Advance Payment";
case "Casual Leave List":
......@@ -469,4 +536,4 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
break;
}
}
}
}
\ No newline at end of file
......@@ -15,8 +15,42 @@ class RewardListScreen extends StatefulWidget {
}
class _RewardListScreenState extends State<RewardListScreen> {
// Responsive text size function
double getResponsiveTextSize(BuildContext context, double baseSize) {
final double width = MediaQuery.of(context).size.width;
if (width < 360) { // Small phones
return baseSize * 0.85;
} else if (width < 400) { // Medium phones
return baseSize;
} else { // Large phones
return baseSize * 1.1;
}
}
// Responsive padding function
double getResponsivePadding(BuildContext context) {
final double width = MediaQuery.of(context).size.width;
return width * 0.04; // 4% of screen width
}
// Responsive height function
double getResponsiveHeight(BuildContext context, double baseHeight) {
final double height = MediaQuery.of(context).size.height;
if (height < 700) { // Small height devices
return baseHeight * 0.85;
} else if (height < 800) { // Medium height devices
return baseHeight;
} else { // Large height devices
return baseHeight * 1.15;
}
}
@override
Widget build(BuildContext context) {
final bool isSmallScreen = MediaQuery.of(context).size.width < 360;
final bool isLargeScreen = MediaQuery.of(context).size.width > 400;
return SafeArea(
top: false,
child: ChangeNotifierProvider(
......@@ -33,14 +67,14 @@ class _RewardListScreenState extends State<RewardListScreen> {
onTap: () => Navigator.pop(context, true),
child: SvgPicture.asset(
"assets/svg/appbar_back_button.svg",
height: 25,
height: isSmallScreen ? 22 : 25,
),
),
const SizedBox(width: 10),
SizedBox(width: isSmallScreen ? 8 : 10),
Text(
"Reward List",
style: TextStyle(
fontSize: 18,
fontSize: getResponsiveTextSize(context, 18),
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w600,
color: AppColors.semi_black,
......@@ -64,10 +98,10 @@ class _RewardListScreenState extends State<RewardListScreen> {
// },
// child: SvgPicture.asset(
// "assets/svg/search_ic.svg",
// height: 25,
// height: isSmallScreen ? 22 : 25,
// ),
// ),
// const SizedBox(width: 20),
// SizedBox(width: isSmallScreen ? 15 : 20),
// ],
),
......@@ -80,10 +114,24 @@ class _RewardListScreenState extends State<RewardListScreen> {
);
}
if (provider.errorMessage != null) {
return Center(child: Text(provider.errorMessage!));
return Center(
child: Text(
provider.errorMessage!,
style: TextStyle(
fontSize: getResponsiveTextSize(context, 14),
),
),
);
}
if (provider.response == null) {
return const Center(child: Text("No details found"));
return Center(
child: Text(
"No details found",
style: TextStyle(
fontSize: getResponsiveTextSize(context, 14),
),
),
);
}
final rewardDetail = provider.response!;
final rewardResponse = provider.response!;
......@@ -93,16 +141,16 @@ class _RewardListScreenState extends State<RewardListScreen> {
final disbursed = rewardResponse.disbursedAmount ?? "0";
final balance = rewardResponse.balanceAmount ?? "0";
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
padding: EdgeInsets.all(getResponsivePadding(context)),
child: Column(
children: [
/// --- Top Summary Cards ---
Stack(
children: [
Container(
height: 110,
height: getResponsiveHeight(context, 110),
width: double.infinity,
padding: const EdgeInsets.all(18),
padding: EdgeInsets.all(isSmallScreen ? 14 : 18),
decoration: BoxDecoration(
color: const Color(0xffd9ffd6),
borderRadius: BorderRadius.circular(18),
......@@ -113,19 +161,19 @@ class _RewardListScreenState extends State<RewardListScreen> {
children: [
Text(
"₹$achieved", // Achieved Amount from response
style: const TextStyle(
fontSize: 20,
color: Color(0xff0D9C00),
style: TextStyle(
fontSize: getResponsiveTextSize(context, 20),
color: const Color(0xff0D9C00),
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 10),
const Text(
SizedBox(height: isSmallScreen ? 6 : 10),
Text(
"Achievement Amount",
style: TextStyle(
fontSize: 14,
color: Color(0xff2D2D2D),
fontSize: getResponsiveTextSize(context, 14),
color: const Color(0xff2D2D2D),
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
),
......@@ -136,19 +184,19 @@ class _RewardListScreenState extends State<RewardListScreen> {
// Positioned SVG Icon
Positioned(
bottom: 8,
right: 12,
bottom: isSmallScreen ? 6 : 8,
right: isSmallScreen ? 10 : 12,
child: Container(
height: 42,
width: 42,
height: isSmallScreen ? 36 : 42,
width: isSmallScreen ? 36 : 42,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: const Color(0xA0FFFFFF), // icon bg
),
child: Center(
child: SvgPicture.asset(
height: 25,
width: 25,
height: isSmallScreen ? 20 : 25,
width: isSmallScreen ? 20 : 25,
"assets/svg/hrm/achievement_ic.svg",
fit: BoxFit.contain,
),
......@@ -157,14 +205,14 @@ class _RewardListScreenState extends State<RewardListScreen> {
),
],
),
const SizedBox(height: 12),
SizedBox(height: isSmallScreen ? 8 : 12),
Row(
children: [
Expanded(
child: Container(
height: 110,
padding: const EdgeInsets.all(16),
height: getResponsiveHeight(context, 110),
padding: EdgeInsets.all(isSmallScreen ? 12 : 16),
decoration: BoxDecoration(
color: const Color(0xffe8ddff),
borderRadius: BorderRadius.circular(16),
......@@ -173,22 +221,22 @@ class _RewardListScreenState extends State<RewardListScreen> {
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
CrossAxisAlignment.start,
children: [
Text(
"₹$disbursed", // Disbursed Amount
style: const TextStyle(
fontSize: 20,
color: Color(0xff493272),
style: TextStyle(
fontSize: getResponsiveTextSize(context, 20),
color: const Color(0xff493272),
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
const Text(
SizedBox(height: isSmallScreen ? 6 : 8),
Text(
"Disbursed \nAmount",
style: TextStyle(
fontSize: 14,
color: Color(0xff2D2D2D),
fontSize: getResponsiveTextSize(context, 14),
color: const Color(0xff2D2D2D),
fontWeight: FontWeight.w400,
),
),
......@@ -198,18 +246,16 @@ class _RewardListScreenState extends State<RewardListScreen> {
bottom: 2,
right: 2,
child: Container(
height: 42,
width: 42,
height: isSmallScreen ? 36 : 42,
width: isSmallScreen ? 36 : 42,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: const Color(
0xA0FFFFFF,
), // icon bg
color: const Color(0xA0FFFFFF),
),
child: Center(
child: SvgPicture.asset(
height: 25,
width: 25,
height: isSmallScreen ? 20 : 25,
width: isSmallScreen ? 20 : 25,
"assets/svg/hrm/location_ic.svg",
fit: BoxFit.contain,
),
......@@ -220,11 +266,11 @@ class _RewardListScreenState extends State<RewardListScreen> {
),
),
),
const SizedBox(width: 12),
SizedBox(width: isSmallScreen ? 8 : 12),
Expanded(
child: Container(
height: 110,
padding: const EdgeInsets.all(16),
height: getResponsiveHeight(context, 110),
padding: EdgeInsets.all(isSmallScreen ? 12 : 16),
decoration: BoxDecoration(
color: const Color(0xfffffbc3),
borderRadius: BorderRadius.circular(16),
......@@ -233,21 +279,21 @@ class _RewardListScreenState extends State<RewardListScreen> {
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
CrossAxisAlignment.start,
children: [
Text(
"₹$balance", // Balance Amount
style: const TextStyle(
fontSize: 18,
color: Color(0xff605C00),
style: TextStyle(
fontSize: getResponsiveTextSize(context, 18),
color: const Color(0xff605C00),
),
),
const SizedBox(height: 8),
const Text(
SizedBox(height: isSmallScreen ? 6 : 8),
Text(
"Balance \nAmount",
style: TextStyle(
fontSize: 14,
color: Color(0xff2D2D2D),
fontSize: getResponsiveTextSize(context, 14),
color: const Color(0xff2D2D2D),
fontWeight: FontWeight.w400,
),
),
......@@ -257,18 +303,16 @@ class _RewardListScreenState extends State<RewardListScreen> {
bottom: 2,
right: 2,
child: Container(
height: 42,
width: 42,
height: isSmallScreen ? 36 : 42,
width: isSmallScreen ? 36 : 42,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: const Color(
0xA0FFFFFF,
), // icon bg
color: const Color(0xA0FFFFFF),
),
child: Center(
child: SvgPicture.asset(
height: 25,
width: 25,
height: isSmallScreen ? 20 : 25,
width: isSmallScreen ? 20 : 25,
"assets/svg/hrm/ballance_ic.svg",
fit: BoxFit.contain,
),
......@@ -282,14 +326,13 @@ class _RewardListScreenState extends State<RewardListScreen> {
],
),
const SizedBox(height: 20),
SizedBox(height: getResponsiveHeight(context, 20)),
/// --- Reward List Card ---
if (rewards != null)
_rewardListCard(
title:
rewards.description ??
"-", // rewardsList fields
context: context,
title: rewards.description ?? "-",
dateTime: rewards.dateTime ?? "-",
achieved: achieved,
disbursed: disbursed,
......@@ -297,7 +340,12 @@ class _RewardListScreenState extends State<RewardListScreen> {
enteredBy: rewards.enteredBy ?? "-",
)
else
const Text("No rewards available"),
Text(
"No rewards available",
style: TextStyle(
fontSize: getResponsiveTextSize(context, 14),
),
),
],
),
);
......@@ -312,6 +360,7 @@ class _RewardListScreenState extends State<RewardListScreen> {
/// Reusable Reward Card Function
Widget _rewardListCard({
required BuildContext context,
required String title,
required String dateTime,
required String achieved,
......@@ -319,19 +368,14 @@ class _RewardListScreenState extends State<RewardListScreen> {
required String balance,
required String enteredBy,
}) {
final bool isSmallScreen = MediaQuery.of(context).size.width < 360;
return Container(
margin: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.all(16),
margin: EdgeInsets.only(bottom: getResponsiveHeight(context, 16)),
padding: EdgeInsets.all(isSmallScreen ? 12 : 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
// boxShadow: [
// BoxShadow(
// color: Colors.grey.withOpacity(0.1),
// blurRadius: 6,
// offset: const Offset(0, 3),
// )
// ],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
......@@ -340,35 +384,38 @@ class _RewardListScreenState extends State<RewardListScreen> {
Row(
children: [
CircleAvatar(
radius: 22.5,
radius: isSmallScreen ? 18 : 22.5,
backgroundColor: Color(0xffEDF8FF),
child: SvgPicture.asset(
height: 28,
width: 28,
height: isSmallScreen ? 22 : 28,
width: isSmallScreen ? 22 : 28,
"assets/svg/hrm/rewardList.svg",
fit: BoxFit.contain,
),
),
const SizedBox(width: 8),
SizedBox(width: isSmallScreen ? 6 : 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 14.5,
color: Color(0xff2D2D2D),
style: TextStyle(
fontSize: getResponsiveTextSize(context, 14.5),
color: const Color(0xff2D2D2D),
fontFamily: "Plus Jakarta Sans",
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: isSmallScreen ? 2 : 4),
Text(
dateTime,
style: const TextStyle(
fontSize: 12.5,
color: Color(0xff818181),
style: TextStyle(
fontSize: getResponsiveTextSize(context, 12.5),
color: const Color(0xff818181),
fontFamily: "Plus Jakarta Sans",
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
......@@ -380,18 +427,21 @@ class _RewardListScreenState extends State<RewardListScreen> {
],
),
const SizedBox(height: 12),
SizedBox(height: isSmallScreen ? 8 : 12),
/// Amount Details
Padding(
padding: const EdgeInsets.all(2.0),
child: Row(
children: [
const Text(
Text(
"Amount Details",
style: TextStyle(fontSize: 14, fontFamily: "JakartaSemiBold"),
style: TextStyle(
fontSize: getResponsiveTextSize(context, 14),
fontFamily: "JakartaSemiBold"
),
),
const SizedBox(width: 10),
SizedBox(width: isSmallScreen ? 6 : 10),
Expanded(
child: DottedLine(
dashGapLength: 4,
......@@ -404,24 +454,27 @@ class _RewardListScreenState extends State<RewardListScreen> {
],
),
),
const SizedBox(height: 6),
SizedBox(height: isSmallScreen ? 4 : 6),
_buildKeyValue("Achieved Amount", achieved),
_buildKeyValue("Disbursed Amount", disbursed),
_buildKeyValue("Balance Amount", balance),
_buildKeyValue(context, "Achieved Amount", achieved),
_buildKeyValue(context, "Disbursed Amount", disbursed),
_buildKeyValue(context, "Balance Amount", balance),
const SizedBox(height: 10),
SizedBox(height: isSmallScreen ? 8 : 10),
/// Employee Details
Padding(
padding: const EdgeInsets.all(2.0),
child: Row(
children: [
const Text(
Text(
"Employee Details",
style: TextStyle(fontSize: 14, fontFamily: "JakartaSemiBold"),
style: TextStyle(
fontSize: getResponsiveTextSize(context, 14),
fontFamily: "JakartaSemiBold"
),
),
const SizedBox(width: 10),
SizedBox(width: isSmallScreen ? 6 : 10),
Expanded(
child: DottedLine(
dashGapLength: 4,
......@@ -435,34 +488,52 @@ class _RewardListScreenState extends State<RewardListScreen> {
),
),
_buildKeyValue("Entered By", enteredBy),
_buildKeyValue(context, "Entered By", enteredBy),
],
),
);
}
/// Key-Value Row
Widget _buildKeyValue(String key, String value) {
Widget _buildKeyValue(BuildContext context, String key, String value) {
final bool isSmallScreen = MediaQuery.of(context).size.width < 360;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 3.5, horizontal: 2),
padding: EdgeInsets.symmetric(
vertical: isSmallScreen ? 2.5 : 3.5,
horizontal: 2
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
key,
style: TextStyle(
fontFamily: "JakartaRegular",
fontSize: 14,
color: AppColors.semi_black,
Expanded(
flex: 2,
child: Text(
key,
style: TextStyle(
fontFamily: "JakartaRegular",
fontSize: getResponsiveTextSize(context, 14),
color: AppColors.semi_black,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
Text(
value,
style: const TextStyle(fontSize: 14, color: Color(0xFF818181)),
Expanded(
flex: 1,
child: Text(
value,
style: TextStyle(
fontSize: getResponsiveTextSize(context, 14),
color: const Color(0xFF818181)
),
textAlign: TextAlign.right,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
);
}
}
}
\ No newline at end of file
......@@ -445,10 +445,10 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
url: "https://pub.dev"
source: hosted
version: "1.3.3"
version: "1.3.2"
ffi:
dependency: transitive
description:
......@@ -1180,26 +1180,26 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
url: "https://pub.dev"
source: hosted
version: "11.0.2"
version: "10.0.8"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
url: "https://pub.dev"
source: hosted
version: "3.0.10"
version: "3.0.9"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
version: "3.0.1"
lints:
dependency: transitive
description:
......@@ -1873,10 +1873,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
url: "https://pub.dev"
source: hosted
version: "0.7.6"
version: "0.7.4"
timezone:
dependency: transitive
description:
......@@ -2017,10 +2017,10 @@ packages:
dependency: transitive
description:
name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
version: "2.1.4"
vm_service:
dependency: transitive
description:
......@@ -2118,5 +2118,5 @@ packages:
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.8.0-0 <3.10.0-z"
dart: ">=3.7.2 <3.10.0-z"
flutter: ">=3.27.0"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment