Refactor dashboard screen layout and improve loading state handling
- Simplified initialization of DynamicMenuController. - Added loading skeleton for employee quick action cards. - Removed daily task planning and daily progress report from card order. - Adjusted grid layout parameters for better responsiveness. - Cleaned up code formatting for improved readability.
This commit is contained in:
parent
3dfa6e5877
commit
8fb32c7c8e
@ -5,7 +5,8 @@ import 'package:on_field_work/helpers/utils/my_shadow.dart';
|
||||
|
||||
class SkeletonLoaders {
|
||||
static Widget buildLoadingSkeleton() {
|
||||
return SizedBox(
|
||||
return ShimmerEffect(
|
||||
child: SizedBox(
|
||||
height: 360,
|
||||
child: Column(
|
||||
children: List.generate(5, (index) {
|
||||
@ -30,10 +31,111 @@ class SkeletonLoaders {
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static Widget attendanceQuickCardSkeleton() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Colors.grey.shade300.withOpacity(0.3),
|
||||
Colors.grey.shade300.withOpacity(0.6),
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
),
|
||||
child: ShimmerEffect(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Row with avatar and texts
|
||||
Row(
|
||||
children: [
|
||||
// Avatar
|
||||
Container(
|
||||
width: 30,
|
||||
height: 30,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade400,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
MySpacing.width(10),
|
||||
// Name + designation
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
height: 12,
|
||||
width: 100,
|
||||
color: Colors.grey.shade400,
|
||||
),
|
||||
MySpacing.height(6),
|
||||
Container(
|
||||
height: 10,
|
||||
width: 70,
|
||||
color: Colors.grey.shade400,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Status
|
||||
Container(
|
||||
height: 12,
|
||||
width: 60,
|
||||
color: Colors.grey.shade400,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Description
|
||||
Container(
|
||||
height: 10,
|
||||
width: double.infinity,
|
||||
color: Colors.grey.shade400,
|
||||
),
|
||||
MySpacing.height(6),
|
||||
Container(
|
||||
height: 10,
|
||||
width: double.infinity,
|
||||
color: Colors.grey.shade400,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Action buttons
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
height: 28,
|
||||
width: 80,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade400,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
),
|
||||
MySpacing.width(8),
|
||||
Container(
|
||||
height: 28,
|
||||
width: 28,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade400,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Inside SkeletonLoaders class
|
||||
static Widget dashboardCardsSkeleton({double? maxWidth}) {
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
double width = maxWidth ?? constraints.maxWidth;
|
||||
@ -50,6 +152,7 @@ class SkeletonLoaders {
|
||||
paddingAll: 4,
|
||||
borderRadiusAll: 5,
|
||||
border: Border.all(color: Colors.grey.withOpacity(0.15)),
|
||||
child: ShimmerEffect(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
@ -69,13 +172,13 @@ class SkeletonLoaders {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Inside SkeletonLoaders class
|
||||
static Widget paymentRequestListSkeletonLoader() {
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.fromLTRB(12, 12, 12, 80),
|
||||
@ -83,7 +186,8 @@ class SkeletonLoaders {
|
||||
separatorBuilder: (_, __) =>
|
||||
Divider(color: Colors.grey.shade300, height: 20),
|
||||
itemBuilder: (context, index) {
|
||||
return Container(
|
||||
return ShimmerEffect(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -163,12 +267,12 @@ class SkeletonLoaders {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Add this inside SkeletonLoaders class
|
||||
static Widget paymentRequestDetailSkeletonLoader() {
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.fromLTRB(12, 12, 12, 30),
|
||||
@ -179,6 +283,7 @@ class SkeletonLoaders {
|
||||
paddingAll: 16,
|
||||
borderRadiusAll: 8,
|
||||
shadow: MyShadow(elevation: 3),
|
||||
child: ShimmerEffect(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -265,7 +370,8 @@ class SkeletonLoaders {
|
||||
MySpacing.width(12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
height: 14,
|
||||
@ -296,10 +402,10 @@ class SkeletonLoaders {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Employee Detail Skeleton Loader
|
||||
static Widget employeeDetailSkeletonLoader() {
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.fromLTRB(12, 20, 12, 80),
|
||||
@ -312,6 +418,7 @@ class SkeletonLoaders {
|
||||
paddingAll: 16,
|
||||
margin: MySpacing.bottom(16),
|
||||
shadow: MyShadow(elevation: 2),
|
||||
child: ShimmerEffect(
|
||||
child: Row(
|
||||
children: [
|
||||
// Avatar
|
||||
@ -350,6 +457,7 @@ class SkeletonLoaders {
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Sections skeleton
|
||||
...List.generate(
|
||||
@ -361,6 +469,7 @@ class SkeletonLoaders {
|
||||
paddingAll: 16,
|
||||
margin: MySpacing.bottom(16),
|
||||
shadow: MyShadow(elevation: 2),
|
||||
child: ShimmerEffect(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -387,8 +496,8 @@ class SkeletonLoaders {
|
||||
...List.generate(
|
||||
2,
|
||||
(_) => Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 12),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
@ -429,14 +538,15 @@ class SkeletonLoaders {
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Daily Progress Planning - Infra (Expanded) Skeleton Loader
|
||||
static Widget dailyProgressPlanningInfraSkeleton() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -446,6 +556,7 @@ class SkeletonLoaders {
|
||||
paddingAll: 5,
|
||||
margin: MySpacing.bottom(10),
|
||||
shadow: MyShadow(elevation: 1.5),
|
||||
child: ShimmerEffect(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -505,7 +616,8 @@ class SkeletonLoaders {
|
||||
height: 10,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderRadius:
|
||||
BorderRadius.circular(4),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -521,12 +633,12 @@ class SkeletonLoaders {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Chart Skeleton Loader (Donut Chart)
|
||||
static Widget chartSkeletonLoader() {
|
||||
return MyCard.bordered(
|
||||
paddingAll: 16,
|
||||
@ -535,6 +647,7 @@ class SkeletonLoaders {
|
||||
elevation: 1.5,
|
||||
position: MyShadowPosition.bottom,
|
||||
),
|
||||
child: ShimmerEffect(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -550,8 +663,7 @@ class SkeletonLoaders {
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Donut Skeleton Placeholder
|
||||
Expanded(
|
||||
child: Center(
|
||||
Center(
|
||||
child: Container(
|
||||
width: 180,
|
||||
height: 180,
|
||||
@ -561,7 +673,6 @@ class SkeletonLoaders {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
@ -582,22 +693,23 @@ class SkeletonLoaders {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Date Skeleton Loader
|
||||
static Widget dateSkeletonLoader() {
|
||||
return Container(
|
||||
return ShimmerEffect(
|
||||
child: Container(
|
||||
height: 14,
|
||||
width: 90,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Expense By Status Skeleton Loader
|
||||
static Widget expenseByStatusSkeletonLoader() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
@ -613,6 +725,7 @@ class SkeletonLoaders {
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ShimmerEffect(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -729,10 +842,10 @@ class SkeletonLoaders {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Document List Skeleton Loader
|
||||
static Widget documentSkeletonLoader() {
|
||||
return Column(
|
||||
children: List.generate(5, (index) {
|
||||
@ -742,6 +855,7 @@ class SkeletonLoaders {
|
||||
// Date placeholder
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
child: ShimmerEffect(
|
||||
child: Container(
|
||||
height: 12,
|
||||
width: 80,
|
||||
@ -751,6 +865,7 @@ class SkeletonLoaders {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Document Card Skeleton
|
||||
Container(
|
||||
@ -767,6 +882,7 @@ class SkeletonLoaders {
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ShimmerEffect(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -820,13 +936,13 @@ class SkeletonLoaders {
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Document Details Card Skeleton Loader
|
||||
static Widget documentDetailsSkeletonLoader() {
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
@ -848,6 +964,7 @@ class SkeletonLoaders {
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ShimmerEffect(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -929,12 +1046,14 @@ class SkeletonLoaders {
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Versions section skeleton
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: ShimmerEffect(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: List.generate(3, (index) {
|
||||
@ -983,12 +1102,12 @@ class SkeletonLoaders {
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Employee List - Card Style
|
||||
static Widget employeeListSkeletonLoader() {
|
||||
return Column(
|
||||
children: List.generate(4, (index) {
|
||||
@ -997,6 +1116,7 @@ class SkeletonLoaders {
|
||||
paddingAll: 10,
|
||||
margin: MySpacing.bottom(12),
|
||||
shadow: MyShadow(elevation: 3),
|
||||
child: ShimmerEffect(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -1022,7 +1142,9 @@ class SkeletonLoaders {
|
||||
color: Colors.grey.shade300),
|
||||
MySpacing.width(8),
|
||||
Container(
|
||||
height: 12, width: 60, color: Colors.grey.shade300),
|
||||
height: 12,
|
||||
width: 60,
|
||||
color: Colors.grey.shade300),
|
||||
],
|
||||
),
|
||||
MySpacing.height(8),
|
||||
@ -1054,16 +1176,17 @@ class SkeletonLoaders {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Employee List - Compact Collapsed Style
|
||||
static Widget employeeListCollapsedSkeletonLoader() {
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
paddingAll: 8,
|
||||
child: ShimmerEffect(
|
||||
child: Column(
|
||||
children: List.generate(4, (index) {
|
||||
return Column(
|
||||
@ -1127,16 +1250,17 @@ class SkeletonLoaders {
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Daily Progress Report Header Loader
|
||||
static Widget dailyProgressReportSkeletonLoader() {
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withOpacity(0.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 8,
|
||||
child: ShimmerEffect(
|
||||
child: Column(
|
||||
children: List.generate(3, (index) {
|
||||
return Column(
|
||||
@ -1158,11 +1282,10 @@ class SkeletonLoaders {
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Daily Progress Planning (Collapsed View)
|
||||
|
||||
static Widget dailyProgressPlanningSkeletonCollapsedOnly() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -1172,6 +1295,7 @@ class SkeletonLoaders {
|
||||
paddingAll: 16,
|
||||
margin: MySpacing.bottom(12),
|
||||
shadow: MyShadow(elevation: 3),
|
||||
child: ShimmerEffect(
|
||||
child: Row(
|
||||
children: [
|
||||
// Icon placeholder
|
||||
@ -1200,6 +1324,7 @@ class SkeletonLoaders {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
@ -1208,11 +1333,12 @@ class SkeletonLoaders {
|
||||
static Widget expenseListSkeletonLoader() {
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.fromLTRB(12, 12, 12, 80),
|
||||
itemCount: 6, // Show 6 skeleton items
|
||||
itemCount: 6,
|
||||
separatorBuilder: (_, __) =>
|
||||
Divider(color: Colors.grey.shade300, height: 20),
|
||||
itemBuilder: (context, index) {
|
||||
return Column(
|
||||
return ShimmerEffect(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Title and Amount
|
||||
@ -1261,6 +1387,7 @@ class SkeletonLoaders {
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -1275,6 +1402,7 @@ class SkeletonLoaders {
|
||||
elevation: 1.5,
|
||||
position: MyShadowPosition.bottom,
|
||||
),
|
||||
child: ShimmerEffect(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -1294,7 +1422,8 @@ class SkeletonLoaders {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(height: 12, width: 120, color: Colors.grey.shade300),
|
||||
Container(
|
||||
height: 12, width: 120, color: Colors.grey.shade300),
|
||||
MySpacing.height(6),
|
||||
Container(height: 10, width: 80, color: Colors.grey.shade300),
|
||||
MySpacing.height(8),
|
||||
@ -1339,9 +1468,11 @@ class SkeletonLoaders {
|
||||
),
|
||||
|
||||
// Arrow
|
||||
Icon(Icons.arrow_forward_ios, size: 14, color: Colors.grey.shade300),
|
||||
Icon(Icons.arrow_forward_ios,
|
||||
size: 14, color: Colors.grey.shade300),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -1354,6 +1485,7 @@ class SkeletonLoaders {
|
||||
elevation: 1.5,
|
||||
position: MyShadowPosition.bottom,
|
||||
),
|
||||
child: ShimmerEffect(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -1396,6 +1528,88 @@ class SkeletonLoaders {
|
||||
Container(height: 10, width: 120, color: Colors.grey.shade300),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A custom reusable Shimmer Effect widget.
|
||||
/// This creates a gradient wave animation over any child widget.
|
||||
class ShimmerEffect extends StatefulWidget {
|
||||
final Widget child;
|
||||
final Color baseColor;
|
||||
final Color highlightColor;
|
||||
|
||||
ShimmerEffect({
|
||||
Key? key,
|
||||
required this.child,
|
||||
Color? baseColor,
|
||||
Color? highlightColor,
|
||||
}) : baseColor = baseColor ?? Colors.grey.shade300,
|
||||
highlightColor = highlightColor ?? Colors.grey.shade100,
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
State<ShimmerEffect> createState() => _ShimmerEffectState();
|
||||
}
|
||||
|
||||
class _ShimmerEffectState extends State<ShimmerEffect>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(seconds: 2), // Adjust speed here
|
||||
)..repeat();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: _controller,
|
||||
child: widget.child,
|
||||
builder: (context, child) {
|
||||
return ShaderMask(
|
||||
blendMode: BlendMode.srcATop,
|
||||
shaderCallback: (bounds) {
|
||||
final gradient = LinearGradient(
|
||||
colors: [
|
||||
widget.baseColor,
|
||||
widget.highlightColor,
|
||||
widget.baseColor,
|
||||
],
|
||||
stops: const [0.1, 0.5, 0.9],
|
||||
begin: const Alignment(-1.0, -0.3),
|
||||
end: const Alignment(1.0, 0.3),
|
||||
transform: _SlidingGradientTransform(_controller.value),
|
||||
);
|
||||
return gradient.createShader(bounds);
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SlidingGradientTransform extends GradientTransform {
|
||||
final double percent;
|
||||
|
||||
const _SlidingGradientTransform(this.percent);
|
||||
|
||||
@override
|
||||
Matrix4? transform(Rect bounds, {TextDirection? textDirection}) {
|
||||
// This moves the gradient across the width of the widget
|
||||
return Matrix4.translationValues(
|
||||
(bounds.width * 2) * percent - bounds.width, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,8 +31,7 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
||||
Get.put(DashboardController(), permanent: true);
|
||||
final AttendanceController attendanceController =
|
||||
Get.put(AttendanceController());
|
||||
final DynamicMenuController menuController =
|
||||
Get.put(DynamicMenuController());
|
||||
final DynamicMenuController menuController = Get.put(DynamicMenuController());
|
||||
final ProjectController projectController = Get.find<ProjectController>();
|
||||
|
||||
bool hasMpin = true;
|
||||
@ -97,6 +96,11 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
||||
children: [
|
||||
_sectionTitle('Quick Action'),
|
||||
Obx(() {
|
||||
if (dashboardController.isLoadingEmployees.value) {
|
||||
// Show loading skeleton
|
||||
return SkeletonLoaders.attendanceQuickCardSkeleton();
|
||||
}
|
||||
|
||||
final employees = dashboardController.employees;
|
||||
final employee = employees.isNotEmpty ? employees.first : null;
|
||||
|
||||
@ -121,6 +125,7 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
||||
);
|
||||
}
|
||||
|
||||
// Actual employee quick action card
|
||||
final bool isCheckedIn = employee.checkIn != null;
|
||||
final bool isCheckedOut = employee.checkOut != null;
|
||||
|
||||
@ -233,8 +238,6 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
||||
final List<String> cardOrder = [
|
||||
MenuItems.attendance,
|
||||
MenuItems.employees,
|
||||
MenuItems.dailyTaskPlanning,
|
||||
MenuItems.dailyProgressReport,
|
||||
MenuItems.directory,
|
||||
MenuItems.finance,
|
||||
MenuItems.documents,
|
||||
@ -247,10 +250,6 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
||||
_DashboardCardMeta(LucideIcons.scan_face, contentTheme.success),
|
||||
MenuItems.employees:
|
||||
_DashboardCardMeta(LucideIcons.users, contentTheme.warning),
|
||||
MenuItems.dailyTaskPlanning:
|
||||
_DashboardCardMeta(LucideIcons.logs, contentTheme.info),
|
||||
MenuItems.dailyProgressReport:
|
||||
_DashboardCardMeta(LucideIcons.list_todo, contentTheme.info),
|
||||
MenuItems.directory:
|
||||
_DashboardCardMeta(LucideIcons.folder, contentTheme.info),
|
||||
MenuItems.finance:
|
||||
@ -314,10 +313,10 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 2),
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 4,
|
||||
crossAxisSpacing: 8,
|
||||
crossAxisCount: 3,
|
||||
crossAxisSpacing: 15,
|
||||
mainAxisSpacing: 8,
|
||||
childAspectRatio: 1.15,
|
||||
childAspectRatio: 1.8,
|
||||
),
|
||||
itemCount: filtered.length,
|
||||
itemBuilder: (context, index) {
|
||||
@ -367,9 +366,8 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
||||
Icon(
|
||||
cardMeta.icon,
|
||||
size: 20,
|
||||
color: isEnabled
|
||||
? cardMeta.color
|
||||
: Colors.grey.shade300,
|
||||
color:
|
||||
isEnabled ? cardMeta.color : Colors.grey.shade300,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Padding(
|
||||
@ -379,9 +377,8 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: isEnabled
|
||||
? FontWeight.w600
|
||||
: FontWeight.w400,
|
||||
fontWeight:
|
||||
isEnabled ? FontWeight.w600 : FontWeight.w400,
|
||||
color: isEnabled
|
||||
? Colors.black87
|
||||
: Colors.grey.shade400,
|
||||
@ -424,11 +421,9 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
||||
children: [
|
||||
_sectionTitle('Project'),
|
||||
GestureDetector(
|
||||
onTap: () =>
|
||||
projectController.isProjectSelectionExpanded.toggle(),
|
||||
onTap: () => projectController.isProjectSelectionExpanded.toggle(),
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 14, vertical: 14),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user