added skeleton for the service and infra list
This commit is contained in:
parent
b907e76c12
commit
3603b12f9c
@ -35,6 +35,143 @@ class SkeletonLoaders {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Widget serviceProjectListSkeletonLoader() {
|
||||||
|
// --- Start: Configuration to match live UI ---
|
||||||
|
// Live UI uses ListView.separated with:
|
||||||
|
// - padding: MySpacing.only(left: 8, right: 8, top: 4, bottom: 120)
|
||||||
|
// - separatorBuilder: MySpacing.height(12)
|
||||||
|
// - _buildProjectCard uses Card(margin: const EdgeInsets.symmetric(horizontal: 6, vertical: 4))
|
||||||
|
|
||||||
|
// To combine:
|
||||||
|
// Horizontal padding: 8 (ListView) + 6 (Card margin) = 14 on each side.
|
||||||
|
// Top/Bottom separation: 4 (ListView padding) + 4 (Card margin) = 8
|
||||||
|
// Separator space: 4 (Card margin) + 12 (Separator) + 4 (Card margin) = 20 total space between cards.
|
||||||
|
|
||||||
|
// New ListView.separated padding to compensate for inner Card margins
|
||||||
|
const EdgeInsets listPadding =
|
||||||
|
const EdgeInsets.fromLTRB(14, 8, 14, 120 + 4); // 8(L/R) + 6(Card L/R Margin) = 14
|
||||||
|
// New separator to match the 12 + 4 * 2 = 20 gap.
|
||||||
|
const Widget cardSeparator = const SizedBox(height: 12);
|
||||||
|
const EdgeInsets cardMargin = EdgeInsets.zero; // Margin is now controlled by the ListView.separated padding
|
||||||
|
|
||||||
|
// Internal Card padding matches the live card
|
||||||
|
const EdgeInsets cardInnerPadding =
|
||||||
|
const EdgeInsets.symmetric(horizontal: 18, vertical: 14);
|
||||||
|
// --- End: Configuration to match live UI ---
|
||||||
|
|
||||||
|
return ListView.separated(
|
||||||
|
padding: listPadding, // Use calculated padding
|
||||||
|
physics:
|
||||||
|
const NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: 4,
|
||||||
|
separatorBuilder: (_, __) => cardSeparator, // Use calculated separator
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Card(
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
|
||||||
|
margin: cardMargin, // Set margin to zero, handled by ListView padding
|
||||||
|
shadowColor: Colors.indigo.withOpacity(0.10),
|
||||||
|
color: Colors.white,
|
||||||
|
child: ShimmerEffect(
|
||||||
|
child: Padding(
|
||||||
|
padding: cardInnerPadding, // Use live card's inner padding
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// 1. Title and Status Row
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
// Project Name Placeholder
|
||||||
|
Container(
|
||||||
|
height: 18, // Matches MyText.titleMedium height approx
|
||||||
|
width: 150,
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
// Status Chip Placeholder
|
||||||
|
Container(
|
||||||
|
height: 18, // Matches status chip height approx
|
||||||
|
width: 60,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
borderRadius: BorderRadius.circular(6),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// MySpacing.height(10) in live UI is the key spacing here
|
||||||
|
// Note: The live UI has MySpacing.height(4) after the title
|
||||||
|
// and then MySpacing.height(10) before the first detail row,
|
||||||
|
// so the total space is 4 + 10 = 14.
|
||||||
|
MySpacing.height(14),
|
||||||
|
|
||||||
|
// 2. Detail Rows (Date, Client, Contact)
|
||||||
|
// Assigned Date Row
|
||||||
|
_buildDetailRowSkeleton(
|
||||||
|
width: 200, iconColor: Colors.teal.shade300),
|
||||||
|
MySpacing.height(8),
|
||||||
|
|
||||||
|
// Client Row
|
||||||
|
_buildDetailRowSkeleton(
|
||||||
|
width: 240, iconColor: Colors.indigo.shade300),
|
||||||
|
MySpacing.height(8),
|
||||||
|
|
||||||
|
// Contact Row
|
||||||
|
_buildDetailRowSkeleton(
|
||||||
|
width: 220, iconColor: Colors.green.shade300),
|
||||||
|
MySpacing.height(12), // MySpacing.height(12) before Wrap
|
||||||
|
|
||||||
|
// 3. Service Chips Wrap
|
||||||
|
Wrap(
|
||||||
|
spacing: 6,
|
||||||
|
runSpacing: 4,
|
||||||
|
children: List.generate(
|
||||||
|
3,
|
||||||
|
(chipIndex) => Container(
|
||||||
|
height: 20,
|
||||||
|
width:
|
||||||
|
70 + (chipIndex * 10).toDouble(), // Varied widths
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors
|
||||||
|
.grey.shade300,
|
||||||
|
borderRadius: BorderRadius.circular(6),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper to build a skeleton row for details
|
||||||
|
static Widget _buildDetailRowSkeleton({
|
||||||
|
required double width,
|
||||||
|
required Color iconColor,
|
||||||
|
}) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
// Icon Placeholder (size 18 matches live UI)
|
||||||
|
Icon(Icons.circle, size: 18, color: iconColor),
|
||||||
|
MySpacing.width(8),
|
||||||
|
// Text Placeholder (height 13 approx for font size 13)
|
||||||
|
Container(
|
||||||
|
height: 14,
|
||||||
|
width: width,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static Widget attendanceQuickCardSkeleton() {
|
static Widget attendanceQuickCardSkeleton() {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import 'package:on_field_work/model/infra_project/infra_project_list.dart';
|
|||||||
import 'package:on_field_work/helpers/widgets/custom_app_bar.dart';
|
import 'package:on_field_work/helpers/widgets/custom_app_bar.dart';
|
||||||
|
|
||||||
import 'package:on_field_work/view/infraProject/infra_project_details_screen.dart';
|
import 'package:on_field_work/view/infraProject/infra_project_details_screen.dart';
|
||||||
|
import 'package:on_field_work/helpers/widgets/my_custom_skeleton.dart';
|
||||||
|
|
||||||
class InfraProjectScreen extends StatefulWidget {
|
class InfraProjectScreen extends StatefulWidget {
|
||||||
const InfraProjectScreen({super.key});
|
const InfraProjectScreen({super.key});
|
||||||
@ -245,7 +246,7 @@ class _InfraProjectScreenState extends State<InfraProjectScreen> with UIMixin {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Obx(() {
|
child: Obx(() {
|
||||||
if (controller.isLoading.value) {
|
if (controller.isLoading.value) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return Center(child: SkeletonLoaders.serviceProjectListSkeletonLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
final projects = controller.filteredProjects;
|
final projects = controller.filteredProjects;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import 'package:on_field_work/model/service_project/service_projects_list_model.
|
|||||||
import 'package:on_field_work/helpers/utils/date_time_utils.dart';
|
import 'package:on_field_work/helpers/utils/date_time_utils.dart';
|
||||||
import 'package:on_field_work/view/service_project/service_project_details_screen.dart';
|
import 'package:on_field_work/view/service_project/service_project_details_screen.dart';
|
||||||
import 'package:on_field_work/helpers/widgets/custom_app_bar.dart';
|
import 'package:on_field_work/helpers/widgets/custom_app_bar.dart';
|
||||||
|
import 'package:on_field_work/helpers/widgets/my_custom_skeleton.dart';
|
||||||
|
|
||||||
class ServiceProjectScreen extends StatefulWidget {
|
class ServiceProjectScreen extends StatefulWidget {
|
||||||
const ServiceProjectScreen({super.key});
|
const ServiceProjectScreen({super.key});
|
||||||
@ -264,7 +265,9 @@ class _ServiceProjectScreenState extends State<ServiceProjectScreen>
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Obx(() {
|
child: Obx(() {
|
||||||
if (controller.isLoading.value) {
|
if (controller.isLoading.value) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return Center(
|
||||||
|
child: SkeletonLoaders
|
||||||
|
.serviceProjectListSkeletonLoader());
|
||||||
}
|
}
|
||||||
final projects = controller.filteredProjects;
|
final projects = controller.filteredProjects;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user