dashboard ui enhancement

export_module_ui_ux_enhancement
Sikander Saleem 3 weeks ago
parent 9c7c178f71
commit 75221bf61f

@ -438,12 +438,13 @@ class CategoryTabs {
static List<CategoryTabs> getTabs({required UsersTypes userType, required BuildContext context}) {
List<CategoryTabs> tabs = [];
if (userType == UsersTypes.engineer) {
// Order: 1-UnAssigned, 2-HighPriority, 3-Overdue, 4-Open, 5-InProgress, 6-Completed
tabs.add(CategoryTabs(label: 'UnAssigned', tag: 1, id: 1, requestType: RequestTypeEnum.unassigned, icon: "dashboard/unassigned", iconColor: AppColor.unassignedStatus(context)));
tabs.add(CategoryTabs(label: context.translation.highPriority, tag: 3, id: 4, requestType: RequestTypeEnum.highPriority, icon: "high_priority", iconColor: AppColor.red30, isHighPriority: true));
tabs.add(CategoryTabs(label: context.translation.overdue, tag: 3, id: 4, requestType: RequestTypeEnum.overdue, icon: "overdue", iconColor: AppColor.yellowIcon(context), isOverDue: true));
tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2, requestType: RequestTypeEnum.open, icon: "dashboard/open_icon", iconColor: AppColor.openColor));
tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3, requestType: RequestTypeEnum.inProgress, icon: "dashboard/inprogress_icon", iconColor: AppColor.primary10));
tabs.add(CategoryTabs(label: 'Completed', tag: 3, id: 4, requestType: RequestTypeEnum.completed, icon: "complete_request", iconColor: AppColor.completedColor));
tabs.add(CategoryTabs(label: context.translation.overdue, tag: 3, id: 4, requestType: RequestTypeEnum.overdue, icon: "overdue", iconColor: AppColor.yellowIcon(context), isOverDue: true));
tabs.add(CategoryTabs(label: context.translation.highPriority, tag: 3, id: 4, requestType: RequestTypeEnum.highPriority, icon: "high_priority", iconColor: AppColor.red30, isHighPriority: true));
return tabs;
}

@ -27,6 +27,7 @@ class _RequestCategoryFragmentState extends State<RequestCategoryFragment> with
late AnimationController _animationController;
late Animation<double> _headerFadeAnimation;
late Animation<Offset> _headerSlideAnimation;
final ScrollController _scrollController = ScrollController();
@override
void initState() {
@ -60,6 +61,7 @@ class _RequestCategoryFragmentState extends State<RequestCategoryFragment> with
@override
void dispose() {
_animationController.dispose();
_scrollController.dispose();
super.dispose();
}
@ -176,36 +178,41 @@ class _RequestCategoryFragmentState extends State<RequestCategoryFragment> with
Widget getTabs({required BuildContext context, required DashBoardProvider requestsProvider, required UsersTypes? userType}) {
List<CategoryTabs> tabs = CategoryTabs.getTabs(userType: userType ?? UsersTypes.normal_user, context: context);
// SizedBox(
// height: 44 + (context.isTablet() ? 36 : 16).toScreenHeight,
// child: ListView.separated(
// scrollDirection: Axis.horizontal,
// separatorBuilder: (cxt, index) => 12.width,
// padding: const EdgeInsets.only(top: 6 + 16, left: 16, right: 16),
// itemBuilder: (cxt, index) {
// return TabButton(
// label: tabs[index].label,
// loading: requestsProvider.isDetailLoading,
// isSelected: requestsProvider.currentListIndex == index,
// count: requestsProvider.requestDetailList != null ? requestsProvider.requestDetailList!.count ?? 0 : 0,
// onPressed: () async {
// setState(() {
// isAscending = false;
// });
// requestsProvider.currentListIndex = index;
// requestsProvider.resetRequestDataList();
// requestsProvider.getRequestDetail(usersType: userType ?? UsersTypes.normal_user, showLoader: true, status: tabs[index].tag, tabId: tabs[index].id);
// },
// );
// },
// itemCount: tabs.length),
// );
return GridView.builder(
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16),
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: context.isTablet() ? 5 : 4, childAspectRatio: 85 / 85, crossAxisSpacing: 8, mainAxisSpacing: 8),
// Calculate item width to show X.5 items (last visible item is exactly 50% visible)
final screenWidth = MediaQuery.of(context).size.width;
final isTablet = context.isTablet();
// Show 3.5 items on phone, 4.5 on tablet (perfect 50% peek)
final visibleItemsWithPeek = isTablet ? 4.5 : 3.5;
const spacing = 4.0;
const horizontalPadding = 16.0;
// Calculate item width: divide available space by visible items including the half item
final availableWidth = screenWidth - (horizontalPadding * 2);
final fullItems = visibleItemsWithPeek.floor(); // 3 or 4
final totalSpacing = (fullItems - 1) * spacing + (spacing * 0.5); // Full gaps + half gap for peek
final itemWidth = (availableWidth - totalSpacing) / visibleItemsWithPeek;
// Check if scrolling is needed
final needsScrolling = tabs.length > fullItems;
return SizedBox(
height: itemWidth + 16, // Height matches item width + bottom padding
child: _buildHorizontalScrollableList(tabs, requestsProvider, userType, itemWidth, needsScrolling),
);
}
// Horizontal scrollable list
Widget _buildHorizontalScrollableList(List<CategoryTabs> tabs, DashBoardProvider requestsProvider, UsersTypes? userType, double itemWidth, bool needsScrolling) {
const leftPadding = 16.0;
const rightPadding = 16.0; // Equal padding - peek is created by item sizing
return ListView.separated(
controller: _scrollController,
scrollDirection: Axis.horizontal,
separatorBuilder: (cxt, index) => const SizedBox(width: 4),
padding: const EdgeInsets.only(bottom: 16, left: leftPadding, right: rightPadding),
itemBuilder: (cxt, index) {
// Calculate staggered animation delay
final delay = index * 0.08;
@ -221,7 +228,7 @@ class _RequestCategoryFragmentState extends State<RequestCategoryFragment> with
);
final slideAnimation = Tween<Offset>(
begin: const Offset(0.0, 0.3),
begin: const Offset(-0.3, 0.0),
end: Offset.zero,
).animate(
CurvedAnimation(
@ -238,28 +245,31 @@ class _RequestCategoryFragmentState extends State<RequestCategoryFragment> with
opacity: animation,
child: SlideTransition(
position: slideAnimation,
child: RequestTypeButton(
label: tabs[index].label,
loading: requestsProvider.isDetailLoading && requestsProvider.currentListIndex == index,
isSelected: requestsProvider.currentListIndex == index,
count: requestsProvider.getStatusCount(tabs[index].requestType),
onPressed: () async {
setState(() {
isAscending = false;
});
requestsProvider.currentListIndex = index;
requestsProvider.resetRequestDataList();
requestsProvider.getRequestDetail(
usersType: userType ?? UsersTypes.normal_user,
showLoader: true,
status: tabs[index].tag,
tabId: tabs[index].id,
isHighPriority: tabs[index].isHighPriority,
isOverdue: tabs[index].isOverDue,
);
},
icon: tabs[index].icon,
iconColor: tabs[index].iconColor,
child: SizedBox(
width: itemWidth, // Use responsive width
child: RequestTypeButton(
label: tabs[index].label,
loading: requestsProvider.isDetailLoading && requestsProvider.currentListIndex == index,
isSelected: requestsProvider.currentListIndex == index,
count: requestsProvider.getStatusCount(tabs[index].requestType),
onPressed: () async {
setState(() {
isAscending = false;
});
requestsProvider.currentListIndex = index;
requestsProvider.resetRequestDataList();
requestsProvider.getRequestDetail(
usersType: userType ?? UsersTypes.normal_user,
showLoader: true,
status: tabs[index].tag,
tabId: tabs[index].id,
isHighPriority: tabs[index].isHighPriority,
isOverdue: tabs[index].isOverDue,
);
},
icon: tabs[index].icon,
iconColor: tabs[index].iconColor,
),
),
),
);

Loading…
Cancel
Save