marco.pms.mobileapp/lib/helpers/widgets/my_custom_skeleton.dart

1133 lines
37 KiB
Dart

import 'package:flutter/material.dart';
import 'package:marco/helpers/widgets/my_card.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/utils/my_shadow.dart';
class SkeletonLoaders {
static Widget buildLoadingSkeleton() {
return SizedBox(
height: 360,
child: Column(
children: List.generate(5, (index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: List.generate(6, (i) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 4),
width: 48,
height: 16,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(6),
),
);
}),
),
),
);
}),
),
);
}
// Inside SkeletonLoaders class
static Widget paymentRequestListSkeletonLoader() {
return ListView.separated(
padding: const EdgeInsets.fromLTRB(12, 12, 12, 80),
itemCount: 6,
separatorBuilder: (_, __) =>
Divider(color: Colors.grey.shade300, height: 20),
itemBuilder: (context, index) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Category name placeholder
Container(
height: 14,
width: 120,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(4),
),
),
const SizedBox(height: 6),
// Payee placeholder
Row(
children: [
Container(
height: 12,
width: 50,
decoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(4),
),
),
const SizedBox(width: 8),
Expanded(
child: Container(
height: 12,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(4),
),
),
),
],
),
const SizedBox(height: 6),
// Due date and status placeholders
Row(
children: [
// Due date label + value
Row(
children: [
Container(
height: 12,
width: 50,
decoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(4),
),
),
const SizedBox(width: 6),
Container(
height: 12,
width: 80,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(4),
),
),
],
),
const Spacer(),
// Status chip placeholder
Container(
height: 20,
width: 60,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(6),
),
),
],
),
],
),
);
},
);
}
// Add this inside SkeletonLoaders class
static Widget paymentRequestDetailSkeletonLoader() {
return SingleChildScrollView(
padding: const EdgeInsets.fromLTRB(12, 12, 12, 30),
child: Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 520),
child: MyCard.bordered(
paddingAll: 16,
borderRadiusAll: 8,
shadow: MyShadow(elevation: 3),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header (Created At + Status)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: 140,
height: 16,
color: Colors.grey.shade300,
),
Container(
width: 80,
height: 20,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(5),
),
),
],
),
MySpacing.height(24),
// Parties Section
...List.generate(
4,
(index) => Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Container(
height: 14,
width: double.infinity,
color: Colors.grey.shade300,
),
)),
MySpacing.height(24),
// Details Table
...List.generate(
6,
(index) => Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Container(
height: 14,
width: double.infinity,
color: Colors.grey.shade300,
),
)),
MySpacing.height(24),
// Documents Section
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(
3,
(index) => Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Container(
height: 40,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(8),
),
),
)),
),
MySpacing.height(24),
// Logs / Timeline
Column(
children: List.generate(
3,
(index) => Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 16,
height: 16,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
),
MySpacing.width(12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 14,
width: 120,
color: Colors.grey.shade300,
),
MySpacing.height(6),
Container(
height: 12,
width: double.infinity,
color: Colors.grey.shade300,
),
MySpacing.height(6),
Container(
height: 12,
width: 80,
color: Colors.grey.shade300,
),
MySpacing.height(16),
],
),
),
],
)),
),
],
),
),
),
),
);
}
// Chart Skeleton Loader (Donut Chart)
static Widget chartSkeletonLoader() {
return MyCard.bordered(
paddingAll: 16,
borderRadiusAll: 12,
shadow: MyShadow(
elevation: 1.5,
position: MyShadowPosition.bottom,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Chart Header Placeholder
Container(
height: 16,
width: 180,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(6),
),
),
const SizedBox(height: 16),
// Donut Skeleton Placeholder
Expanded(
child: Center(
child: Container(
width: 180,
height: 180,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey.shade300.withOpacity(0.5),
),
),
),
),
const SizedBox(height: 16),
// Legend placeholders
Wrap(
spacing: 8,
runSpacing: 8,
children: List.generate(5, (index) {
return Container(
width: 100,
height: 14,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(6),
),
);
}),
),
],
),
);
}
// Date Skeleton Loader
static Widget dateSkeletonLoader() {
return 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),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.05),
blurRadius: 6,
spreadRadius: 1,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Title
Container(
height: 16,
width: 160,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(6),
),
),
const SizedBox(height: 16),
// 4 Status Rows
...List.generate(4, (index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
children: [
// Icon placeholder
Container(
height: 44,
width: 44,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
),
const SizedBox(width: 12),
// Title + Amount
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 12,
width: 100,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(4),
),
),
const SizedBox(height: 6),
Container(
height: 12,
width: 60,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(4),
),
),
],
),
),
// Count + arrow placeholder
Container(
height: 12,
width: 30,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(4),
),
),
const SizedBox(width: 6),
Icon(Icons.chevron_right,
color: Colors.grey.shade300, size: 24),
],
),
);
}),
const SizedBox(height: 16),
Divider(color: Colors.grey.shade300),
const SizedBox(height: 12),
// Bottom Row (Project Spendings)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 12,
width: 120,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(4),
),
),
const SizedBox(height: 4),
Container(
height: 10,
width: 140,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(4),
),
),
],
),
Container(
height: 16,
width: 80,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(4),
),
),
],
),
],
),
);
}
// Document List Skeleton Loader
static Widget documentSkeletonLoader() {
return Column(
children: List.generate(5, (index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Date placeholder
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
child: Container(
height: 12,
width: 80,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(6),
),
),
),
// Document Card Skeleton
Container(
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Icon Placeholder
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(8),
),
child: const Icon(Icons.description,
color: Colors.transparent), // invisible icon
),
const SizedBox(width: 12),
// Text placeholders
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 12,
width: 80,
color: Colors.grey.shade300,
),
MySpacing.height(6),
Container(
height: 14,
width: double.infinity,
color: Colors.grey.shade300,
),
MySpacing.height(6),
Container(
height: 12,
width: 100,
color: Colors.grey.shade300,
),
],
),
),
// Action icon placeholder
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
),
],
),
),
],
);
}),
);
}
// Document Details Card Skeleton Loader
static Widget documentDetailsSkeletonLoader() {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Details Card
Container(
constraints: const BoxConstraints(maxWidth: 460),
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.06),
blurRadius: 16,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Row(
children: [
Container(
width: 56,
height: 56,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 16,
width: 180,
color: Colors.grey.shade300,
),
const SizedBox(height: 8),
Container(
height: 12,
width: 120,
color: Colors.grey.shade300,
),
],
),
),
],
),
const SizedBox(height: 12),
// Tags placeholder
Wrap(
spacing: 6,
runSpacing: 6,
children: List.generate(3, (index) {
return Container(
height: 20,
width: 60,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(12),
),
);
}),
),
const SizedBox(height: 16),
// Info rows placeholders
Column(
children: List.generate(10, (index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
children: [
Container(
height: 12,
width: 120,
color: Colors.grey.shade300,
),
const SizedBox(width: 12),
Expanded(
child: Container(
height: 12,
color: Colors.grey.shade300,
),
),
],
),
);
}),
),
],
),
),
const SizedBox(height: 20),
// Versions section skeleton
Container(
margin: const EdgeInsets.symmetric(horizontal: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(3, (index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(8),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 12,
width: 180,
color: Colors.grey.shade300,
),
const SizedBox(height: 6),
Container(
height: 10,
width: 120,
color: Colors.grey.shade300,
),
],
),
),
Container(
width: 24,
height: 24,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
),
],
),
);
}),
),
),
],
),
);
}
// Employee List - Card Style
static Widget employeeListSkeletonLoader() {
return Column(
children: List.generate(4, (index) {
return MyCard.bordered(
borderRadiusAll: 12,
paddingAll: 10,
margin: MySpacing.bottom(12),
shadow: MyShadow(elevation: 3),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Avatar
Container(
width: 41,
height: 41,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
),
MySpacing.width(16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
height: 14,
width: 100,
color: Colors.grey.shade300),
MySpacing.width(8),
Container(
height: 12, width: 60, color: Colors.grey.shade300),
],
),
MySpacing.height(8),
Row(
children: [
Icon(Icons.email,
size: 16, color: Colors.grey.shade300),
MySpacing.width(4),
Container(
height: 10,
width: 140,
color: Colors.grey.shade300),
],
),
MySpacing.height(8),
Row(
children: [
Icon(Icons.phone,
size: 16, color: Colors.grey.shade300),
MySpacing.width(4),
Container(
height: 10,
width: 100,
color: Colors.grey.shade300),
],
),
],
),
),
],
),
);
}),
);
}
// Employee List - Compact Collapsed Style
static Widget employeeListCollapsedSkeletonLoader() {
return MyCard.bordered(
borderRadiusAll: 4,
paddingAll: 8,
child: Column(
children: List.generate(4, (index) {
return Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
children: [
// Avatar
Container(
width: 31,
height: 31,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
),
MySpacing.width(16),
// Name, Designation & Buttons
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 12,
width: 100,
color: Colors.grey.shade300),
MySpacing.height(8),
Container(
height: 10,
width: 80,
color: Colors.grey.shade300),
MySpacing.height(12),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
height: 28,
width: 60,
color: Colors.grey.shade300),
MySpacing.width(8),
Container(
height: 28,
width: 60,
color: Colors.grey.shade300),
],
),
],
),
),
],
),
),
if (index != 3)
Divider(
color: Colors.grey.withOpacity(0.3),
thickness: 1,
height: 1,
),
],
);
}),
),
);
}
// 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: Column(
children: List.generate(3, (index) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: 14, width: 120, color: Colors.grey.shade300),
Icon(Icons.add_circle, color: Colors.grey.shade300),
],
),
if (index != 2) ...[
MySpacing.height(12),
Divider(color: Colors.grey.withOpacity(0.3), thickness: 1),
MySpacing.height(12),
],
],
);
}),
),
);
}
// Daily Progress Planning (Collapsed View)
static Widget dailyProgressPlanningSkeletonCollapsedOnly() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(3, (index) {
return MyCard.bordered(
borderRadiusAll: 12,
paddingAll: 16,
margin: MySpacing.bottom(12),
shadow: MyShadow(elevation: 3),
child: Row(
children: [
// Icon placeholder
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
),
MySpacing.width(12),
// Text line
Expanded(
child: Container(height: 16, color: Colors.grey.shade300),
),
MySpacing.width(12),
// Expand button placeholder
Container(
width: 28,
height: 28,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey.shade300,
),
),
],
),
);
}),
);
}
static Widget expenseListSkeletonLoader() {
return ListView.separated(
padding: const EdgeInsets.fromLTRB(12, 12, 12, 80),
itemCount: 6, // Show 6 skeleton items
separatorBuilder: (_, __) =>
Divider(color: Colors.grey.shade300, height: 20),
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Title and Amount
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: 14,
width: 120,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(6),
),
),
Container(
height: 14,
width: 80,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(6),
),
),
],
),
const SizedBox(height: 6),
// Date and Status
Row(
children: [
Container(
height: 12,
width: 100,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(6),
),
),
const Spacer(),
Container(
height: 12,
width: 50,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(6),
),
),
],
),
],
);
},
);
}
static Widget employeeSkeletonCard() {
return MyCard.bordered(
margin: MySpacing.only(bottom: 12),
paddingAll: 12,
borderRadiusAll: 12,
shadow: MyShadow(
elevation: 1.5,
position: MyShadowPosition.bottom,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Avatar
Container(
height: 35,
width: 35,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
),
MySpacing.width(12),
// Name, org, email, phone
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(height: 12, width: 120, color: Colors.grey.shade300),
MySpacing.height(6),
Container(height: 10, width: 80, color: Colors.grey.shade300),
MySpacing.height(8),
// Email placeholder
Row(
children: [
Icon(Icons.email_outlined,
size: 14, color: Colors.grey.shade300),
MySpacing.width(4),
Container(
height: 10, width: 140, color: Colors.grey.shade300),
],
),
MySpacing.height(8),
// Phone placeholder
Row(
children: [
Icon(Icons.phone_outlined,
size: 14, color: Colors.grey.shade300),
MySpacing.width(4),
Container(
height: 10, width: 100, color: Colors.grey.shade300),
MySpacing.width(8),
Container(
height: 16,
width: 16,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
),
],
),
MySpacing.height(8),
// Tags placeholder
Container(height: 8, width: 80, color: Colors.grey.shade300),
],
),
),
// Arrow
Icon(Icons.arrow_forward_ios, size: 14, color: Colors.grey.shade300),
],
),
);
}
static Widget contactSkeletonCard() {
return MyCard.bordered(
margin: MySpacing.only(bottom: 12),
paddingAll: 16,
borderRadiusAll: 16,
shadow: MyShadow(
elevation: 1.5,
position: MyShadowPosition.bottom,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
height: 40,
width: 40,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
),
MySpacing.width(12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 12,
width: 100,
color: Colors.grey.shade300,
),
MySpacing.height(6),
Container(
height: 10,
width: 60,
color: Colors.grey.shade300,
),
],
),
),
],
),
MySpacing.height(16),
Container(height: 10, width: 150, color: Colors.grey.shade300),
MySpacing.height(8),
Container(height: 10, width: 100, color: Colors.grey.shade300),
MySpacing.height(8),
Container(height: 10, width: 120, color: Colors.grey.shade300),
],
),
);
}
}