feat: Refactor project selection handling and update UI across various screens

This commit is contained in:
Vaibhav Surve 2025-06-12 11:31:36 +05:30
parent b81ac33b2d
commit 56efbe8869
6 changed files with 492 additions and 385 deletions

View File

@ -10,12 +10,17 @@ class ProjectController extends GetxController {
RxList<ProjectModel> projects = <ProjectModel>[].obs;
RxString? selectedProjectId;
RxBool isProjectListExpanded = false.obs;
RxBool isProjectSelectionExpanded = false.obs;
RxBool isProjectSelectionExpanded = false.obs;
RxBool isProjectDropdownExpanded = false.obs;
RxBool isLoading = true.obs;
RxBool isLoadingProjects = true.obs;
RxMap<String, RxBool> uploadingStates = <String, RxBool>{}.obs;
ProjectModel? get selectedProject {
if (selectedProjectId == null || selectedProjectId!.value.isEmpty)
return null;
return projects.firstWhereOrNull((p) => p.id == selectedProjectId!.value);
}
@override
void onInit() {
@ -57,6 +62,6 @@ class ProjectController extends GetxController {
Future<void> updateSelectedProject(String projectId) async {
selectedProjectId?.value = projectId;
await LocalStorage.saveString('selectedProjectId', projectId);
update();
update();
}
}

View File

@ -3,15 +3,12 @@ import 'package:get/get.dart';
import 'package:marco/helpers/theme/app_theme.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
import 'package:marco/helpers/utils/my_shadow.dart';
import 'package:marco/helpers/widgets/my_breadcrumb.dart';
import 'package:marco/helpers/widgets/my_breadcrumb_item.dart';
import 'package:marco/helpers/widgets/my_card.dart';
import 'package:marco/helpers/widgets/my_container.dart';
import 'package:marco/helpers/widgets/my_flex.dart';
import 'package:marco/helpers/widgets/my_flex_item.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/view/layouts/layout.dart';
import 'package:marco/controller/dashboard/attendance_screen_controller.dart';
import 'package:marco/controller/permission_controller.dart';
import 'package:intl/intl.dart';
@ -20,7 +17,7 @@ import 'package:marco/model/attendance/log_details_view.dart';
import 'package:marco/model/attendance/attendence_action_button.dart';
import 'package:marco/model/attendance/regualrize_action_button.dart';
import 'package:marco/model/attendance/attendence_filter_sheet.dart';
import 'package:marco/controller/project_controller.dart'; // adjust if needed
import 'package:marco/controller/project_controller.dart';
class AttendanceScreen extends StatefulWidget {
AttendanceScreen({super.key});
@ -57,169 +54,198 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
@override
Widget build(BuildContext context) {
return Layout(
child: GetBuilder<AttendanceController>(
init: attendanceController,
tag: 'attendance_dashboard_controller',
builder: (controller) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: MySpacing.x(flexSpacing),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MyText.titleMedium("Attendance",
fontSize: 18, fontWeight: 600),
MyBreadcrumb(
children: [
MyBreadcrumbItem(name: 'Dashboard'),
MyBreadcrumbItem(name: 'Attendance', active: true),
],
),
],
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: AppBar(
backgroundColor: const Color(0xFFF5F5F5),
elevation: 0.5,
foregroundColor: Colors.black,
titleSpacing: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new,
color: Colors.black, size: 20),
onPressed: () {
Get.offNamed('/dashboard');
},
),
title: Padding(
padding: const EdgeInsets.only(top: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
MyText.titleLarge(
'Attendance',
fontWeight: 700,
color: Colors.black,
),
),
MySpacing.height(flexSpacing),
Row(
mainAxisAlignment: MainAxisAlignment.end,
const SizedBox(height: 4),
GetBuilder<ProjectController>(
builder: (projectController) {
final projectName =
projectController.selectedProject?.name ??
'Select Project';
return MyText.bodySmall(
projectName,
fontWeight: 600,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: Colors.grey[700],
);
},
),
],
),
),
),
),
body: SafeArea(
child: SingleChildScrollView(
padding: MySpacing.x(0),
child: GetBuilder<AttendanceController>(
init: attendanceController,
tag: 'attendance_dashboard_controller',
builder: (controller) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.bodyMedium(
"Filter",
fontWeight: 600,
),
Tooltip(
message: 'Filter Project',
child: InkWell(
borderRadius: BorderRadius.circular(24),
onTap: () async {
final result =
await showModalBottomSheet<Map<String, dynamic>>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.vertical(top: Radius.circular(12)),
),
builder: (context) => AttendanceFilterBottomSheet(
controller: attendanceController,
permissionController: permissionController,
selectedTab: selectedTab,
),
);
MySpacing.height(flexSpacing),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
MyText.bodyMedium("Filter", fontWeight: 600),
Tooltip(
message: 'Filter Project',
child: InkWell(
borderRadius: BorderRadius.circular(24),
onTap: () async {
final result = await showModalBottomSheet<
Map<String, dynamic>>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(12)),
),
builder: (context) => AttendanceFilterBottomSheet(
controller: attendanceController,
permissionController: permissionController,
selectedTab: selectedTab,
),
);
if (result != null) {
final selectedProjectId =
Get.find<ProjectController>()
.selectedProjectId
?.value;
if (result != null) {
final selectedProjectId =
Get.find<ProjectController>()
.selectedProjectId
?.value;
final selectedView = result['selectedTab'] as String?;
final selectedView =
result['selectedTab'] as String?;
if (selectedProjectId != null &&
selectedProjectId !=
attendanceController.selectedProjectId) {
attendanceController.selectedProjectId =
selectedProjectId;
try {
await attendanceController
.fetchEmployeesByProject(selectedProjectId);
await attendanceController
.fetchAttendanceLogs(selectedProjectId);
await attendanceController
.fetchRegularizationLogs(selectedProjectId);
await attendanceController
.fetchProjectData(selectedProjectId);
} catch (_) {}
attendanceController
.update(['attendance_dashboard_controller']);
}
if (selectedProjectId != null &&
selectedProjectId !=
attendanceController.selectedProjectId) {
attendanceController.selectedProjectId =
selectedProjectId;
try {
await attendanceController
.fetchEmployeesByProject(
selectedProjectId);
await attendanceController
.fetchAttendanceLogs(selectedProjectId);
await attendanceController
.fetchRegularizationLogs(
selectedProjectId);
await attendanceController
.fetchProjectData(selectedProjectId);
} catch (_) {}
attendanceController.update(
['attendance_dashboard_controller']);
}
if (selectedView != null &&
selectedView != selectedTab) {
setState(() {
selectedTab = selectedView;
});
}
}
},
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.filter_list_alt,
color: Colors.blueAccent,
size: 28,
if (selectedView != null &&
selectedView != selectedTab) {
setState(() {
selectedTab = selectedView;
});
}
}
},
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.filter_list_alt,
color: Colors.blueAccent,
size: 28,
),
),
),
),
),
),
),
const SizedBox(width: 4),
MyText.bodyMedium(
"Refresh",
fontWeight: 600,
),
Tooltip(
message: 'Refresh Data',
child: InkWell(
borderRadius: BorderRadius.circular(24),
onTap: () async {
final projectId = Get.find<ProjectController>()
.selectedProjectId
?.value;
const SizedBox(width: 4),
MyText.bodyMedium("Refresh", fontWeight: 600),
Tooltip(
message: 'Refresh Data',
child: InkWell(
borderRadius: BorderRadius.circular(24),
onTap: () async {
final projectId = Get.find<ProjectController>()
.selectedProjectId
?.value;
if (projectId != null && projectId.isNotEmpty) {
try {
await attendanceController
.fetchEmployeesByProject(projectId);
await attendanceController
.fetchAttendanceLogs(projectId);
await attendanceController
.fetchRegularizationLogs(projectId);
await attendanceController
.fetchProjectData(projectId);
attendanceController
.update(['attendance_dashboard_controller']);
} catch (e) {
debugPrint("Error refreshing data: $e");
}
}
},
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.refresh,
color: Colors.green,
size: 28,
if (projectId != null && projectId.isNotEmpty) {
try {
await attendanceController
.fetchEmployeesByProject(projectId);
await attendanceController
.fetchAttendanceLogs(projectId);
await attendanceController
.fetchRegularizationLogs(projectId);
await attendanceController
.fetchProjectData(projectId);
attendanceController.update(
['attendance_dashboard_controller']);
} catch (e) {
debugPrint("Error refreshing data: $e");
}
}
},
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.refresh,
color: Colors.green,
size: 28,
),
),
),
),
),
),
],
),
MySpacing.height(flexSpacing),
MyFlex(children: [
MyFlexItem(
sizes: 'lg-12 md-12 sm-12',
child: selectedTab == 'todaysAttendance'
? employeeListTab()
: selectedTab == 'attendanceLogs'
? employeeLog()
: regularizationScreen(),
),
]),
],
),
Padding(
padding: MySpacing.x(0),
child: MyFlex(children: [
MyFlexItem(
sizes: 'lg-12 md-12 sm-12',
child: selectedTab == 'todaysAttendance'
? employeeListTab()
: selectedTab == 'attendanceLogs'
? employeeLog()
: regularizationScreen(),
),
]),
),
],
);
},
);
},
),
),
),
);
}

View File

@ -8,14 +8,13 @@ import 'package:marco/helpers/widgets/my_breadcrumb_item.dart';
import 'package:marco/helpers/widgets/my_card.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/view/layouts/layout.dart';
import 'package:marco/controller/permission_controller.dart';
import 'package:marco/model/employees/employees_screen_filter_sheet.dart';
import 'package:marco/model/employees/add_employee_bottom_sheet.dart';
import 'package:marco/controller/dashboard/employees_screen_controller.dart';
import 'package:marco/helpers/widgets/avatar.dart';
import 'package:marco/model/employees/employee_detail_bottom_sheet.dart';
import 'package:marco/controller/project_controller.dart';
class EmployeesScreen extends StatefulWidget {
const EmployeesScreen({super.key});
@ -79,7 +78,52 @@ class _EmployeesScreenState extends State<EmployeesScreen> with UIMixin {
@override
Widget build(BuildContext context) {
return Layout(
return Scaffold(
backgroundColor: const Color(0xFFF5F5F5),
appBar: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: AppBar(
backgroundColor: const Color(0xFFF5F5F5),
elevation: 0.5,
foregroundColor: Colors.black,
titleSpacing: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new),
onPressed: () {
Get.offNamed('/dashboard');
},
),
title: Padding(
padding: const EdgeInsets.only(top: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
MyText.titleLarge(
'Employees',
fontWeight: 700,
color: Colors.black,
),
const SizedBox(height: 4),
GetBuilder<ProjectController>(
builder: (projectController) {
final projectName =
projectController.selectedProject?.name ??
'Select Project';
return MyText.bodySmall(
projectName,
fontWeight: 600,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: Colors.grey[700],
);
},
),
],
),
),
),
),
floatingActionButton: InkWell(
onTap: () async {
final result = await showModalBottomSheet<bool>(
@ -120,13 +164,14 @@ class _EmployeesScreenState extends State<EmployeesScreen> with UIMixin {
),
),
),
child: GetBuilder<EmployeesScreenController>(
init: employeeScreenController,
tag: 'employee_screen_controller',
builder: (controller) {
return Stack(
children: [
Column(
body: SafeArea(
child: GetBuilder<EmployeesScreenController>(
init: employeeScreenController,
tag: 'employee_screen_controller',
builder: (controller) {
return SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 80),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
@ -134,11 +179,6 @@ class _EmployeesScreenState extends State<EmployeesScreen> with UIMixin {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MyText.titleMedium(
"Employees",
fontSize: 18,
fontWeight: 600,
),
MyBreadcrumb(
children: [
MyBreadcrumbItem(name: 'Dashboard'),
@ -154,10 +194,7 @@ class _EmployeesScreenState extends State<EmployeesScreen> with UIMixin {
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
MyText.bodyMedium(
"Filter",
fontWeight: 600,
),
MyText.bodyMedium("Filter", fontWeight: 600),
Tooltip(
message: 'Project',
child: InkWell(
@ -177,10 +214,7 @@ class _EmployeesScreenState extends State<EmployeesScreen> with UIMixin {
),
),
const SizedBox(width: 8),
MyText.bodyMedium(
"Refresh",
fontWeight: 600,
),
MyText.bodyMedium("Refresh", fontWeight: 600),
Tooltip(
message: 'Refresh Data',
child: InkWell(
@ -208,9 +242,9 @@ class _EmployeesScreenState extends State<EmployeesScreen> with UIMixin {
),
],
),
],
);
},
);
},
),
),
);
}

View File

@ -9,6 +9,7 @@ import 'package:marco/helpers/services/api_endpoints.dart';
import 'package:marco/images.dart';
import 'package:marco/controller/project_controller.dart';
import 'package:marco/view/layouts/user_profile_right_bar.dart';
class Layout extends StatefulWidget {
final Widget? child;
final Widget? floatingActionButton;
@ -42,7 +43,7 @@ class _LayoutState extends State<Layout> {
Widget _buildScaffold(BuildContext context, {bool isMobile = false}) {
return Scaffold(
key: controller.scaffoldKey,
endDrawer: UserProfileBar(),
endDrawer: UserProfileBar(),
floatingActionButton: widget.floatingActionButton,
body: SafeArea(
child: Column(
@ -51,8 +52,8 @@ class _LayoutState extends State<Layout> {
Expanded(
child: SingleChildScrollView(
key: controller.scrollKey,
padding: EdgeInsets.symmetric(horizontal: 0, vertical: isMobile ? 16 : 32),
padding: EdgeInsets.symmetric(
horizontal: 0, vertical: isMobile ? 16 : 32),
child: widget.child,
),
),
@ -64,7 +65,7 @@ class _LayoutState extends State<Layout> {
Widget _buildHeader(BuildContext context, bool isMobile) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 0),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
child: Obx(() {
final isExpanded = projectController.isProjectSelectionExpanded.value;
final selectedProjectId = projectController.selectedProjectId?.value;
@ -77,102 +78,96 @@ class _LayoutState extends State<Layout> {
.updateSelectedProject(projectController.projects.first.id);
}
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(isExpanded ? 16 : 0),
),
boxShadow: [
BoxShadow(
color: const Color.fromARGB(255, 67, 73, 84),
blurRadius: 4,
offset: Offset(0, 2),
),
],
return Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(isExpanded ? 16 : 12),
),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.asset(
Images.logoDark,
height: 50,
width: 50,
fit: BoxFit.contain,
margin: EdgeInsets.zero,
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.asset(
Images.logoDark,
height: 50,
width: 50,
fit: BoxFit.contain,
),
),
),
const SizedBox(width: 12),
Expanded(
child: GestureDetector(
onTap: () =>
projectController.isProjectSelectionExpanded.toggle(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Row(
children: [
Expanded(
child: MyText.bodyLarge(
selectedProject?.name ??
"Select Project",
fontWeight: 700,
maxLines: 1,
overflow: TextOverflow.ellipsis,
const SizedBox(width: 12),
Expanded(
child: GestureDetector(
onTap: () => projectController
.isProjectSelectionExpanded
.toggle(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Row(
children: [
Expanded(
child: MyText.bodyLarge(
selectedProject?.name ??
"Select Project",
fontWeight: 700,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
),
Icon(
isExpanded
? Icons.arrow_drop_up_outlined
: Icons.arrow_drop_down_outlined,
color: Colors.black,
),
],
Icon(
isExpanded
? Icons.arrow_drop_up_outlined
: Icons.arrow_drop_down_outlined,
color: Colors.black,
),
],
),
),
),
],
),
MyText.bodyMedium(
"Hi, ${employeeInfo?.firstName ?? ''}",
color: Colors.black54,
),
],
],
),
MyText.bodyMedium(
"Hi, ${employeeInfo?.firstName ?? ''}",
color: Colors.black54,
),
],
),
),
),
),
if (isBetaEnvironment)
Container(
margin: const EdgeInsets.only(left: 8),
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: Colors.deepPurple,
borderRadius: BorderRadius.circular(6),
),
child: MyText.bodySmall(
'BETA',
color: Colors.white,
fontWeight: 700,
if (isBetaEnvironment)
Container(
margin: const EdgeInsets.only(left: 8),
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: Colors.deepPurple,
borderRadius: BorderRadius.circular(6),
),
child: MyText.bodySmall(
'BETA',
color: Colors.white,
fontWeight: 700,
),
),
IconButton(
icon: Icon(Icons.menu),
onPressed: () =>
controller.scaffoldKey.currentState?.openEndDrawer(),
),
IconButton(
icon: Icon(Icons.menu),
onPressed: () =>
controller.scaffoldKey.currentState?.openEndDrawer(),
),
],
),
const SizedBox(height: 8),
if (isExpanded) _buildProjectList(context, isMobile),
],
],
),
const SizedBox(height: 8),
if (isExpanded) _buildProjectList(context, isMobile),
],
),
),
);
}),

View File

@ -4,13 +4,10 @@ import 'package:intl/intl.dart';
import 'package:marco/helpers/theme/app_theme.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
import 'package:marco/helpers/utils/my_shadow.dart';
import 'package:marco/helpers/widgets/my_breadcrumb.dart';
import 'package:marco/helpers/widgets/my_breadcrumb_item.dart';
import 'package:marco/helpers/widgets/my_card.dart';
import 'package:marco/helpers/widgets/my_container.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/view/layouts/layout.dart';
import 'package:marco/controller/permission_controller.dart';
import 'package:marco/controller/dashboard/daily_task_controller.dart';
import 'package:marco/model/dailyTaskPlaning/daily_progress_report_filter.dart';
@ -68,47 +65,74 @@ class _DailyProgressReportScreenState extends State<DailyProgressReportScreen>
@override
Widget build(BuildContext context) {
return Layout(
child: GetBuilder<DailyTaskController>(
init: dailyTaskController,
tag: 'daily_progress_report_controller',
builder: (controller) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(),
MySpacing.height(flexSpacing),
_buildActionBar(),
Padding(
padding: MySpacing.x(flexSpacing),
child: _buildDailyProgressReportTab(),
),
],
);
},
),
);
}
Widget _buildHeader() {
return Padding(
padding: MySpacing.x(flexSpacing),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MyText.titleMedium("Daily Progress Report",
fontSize: 18, fontWeight: 600),
MyBreadcrumb(
children: [
MyBreadcrumbItem(name: 'Dashboard'),
MyBreadcrumbItem(name: 'Daily Progress Report', active: true),
],
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: AppBar(
backgroundColor: const Color(0xFFF5F5F5),
elevation: 0.5,
foregroundColor: Colors.black,
titleSpacing: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new),
onPressed: () {
Get.offNamed('/dashboard');
},
),
],
title: Padding(
padding: const EdgeInsets.only(top: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.titleLarge(
'Daily Task Progress Report',
fontWeight: 700,
color: Colors.black,
),
const SizedBox(height: 4),
GetBuilder<ProjectController>(
builder: (projectController) {
final projectName =
projectController.selectedProject?.name ??
'Select Project';
return MyText.bodySmall(
projectName,
fontWeight: 600,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: Colors.grey[700],
);
},
),
],
),
),
),
),
body: SafeArea(
child: SingleChildScrollView(
padding: MySpacing.x(0),
child: GetBuilder<DailyTaskController>(
init: dailyTaskController,
tag: 'daily_progress_report_controller',
builder: (controller) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MySpacing.height(flexSpacing),
_buildActionBar(),
Padding(
padding: MySpacing.x(flexSpacing),
child: _buildDailyProgressReportTab(),
),
],
);
},
),
),
),
);
}
Widget _buildActionBar() {
return Padding(
padding: MySpacing.x(flexSpacing),

View File

@ -3,12 +3,9 @@ import 'package:get/get.dart';
import 'package:marco/helpers/theme/app_theme.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
import 'package:marco/helpers/utils/my_shadow.dart';
import 'package:marco/helpers/widgets/my_breadcrumb.dart';
import 'package:marco/helpers/widgets/my_breadcrumb_item.dart';
import 'package:marco/helpers/widgets/my_card.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/view/layouts/layout.dart';
import 'package:marco/controller/permission_controller.dart';
import 'package:marco/controller/task_planing/daily_task_planing_controller.dart';
import 'package:marco/controller/project_controller.dart';
@ -50,82 +47,108 @@ class _DailyTaskPlaningScreenState extends State<DailyTaskPlaningScreen>
@override
Widget build(BuildContext context) {
return Layout(
child: GetBuilder<DailyTaskPlaningController>(
init: dailyTaskPlaningController,
tag: 'daily_task_planing_controller',
builder: (controller) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: MySpacing.x(flexSpacing),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MyText.titleMedium("Daily Task Planning",
fontSize: 18, fontWeight: 600),
MyBreadcrumb(
children: [
MyBreadcrumbItem(name: 'Dashboard'),
MyBreadcrumbItem(
name: 'Daily Task Planning', active: true),
],
),
],
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: AppBar(
backgroundColor: const Color(0xFFF5F5F5),
elevation: 0.5,
foregroundColor: Colors.black,
titleSpacing: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new),
onPressed: () {
Get.offNamed('/dashboard');
},
),
title: Padding(
padding: const EdgeInsets.only(top: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
MyText.titleLarge(
'Daily Task Planning',
fontWeight: 700,
color: Colors.black,
),
),
MySpacing.height(flexSpacing),
Padding(
padding: MySpacing.x(flexSpacing),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
const SizedBox(width: 8),
MyText.bodyMedium(
"Refresh",
const SizedBox(height: 4),
GetBuilder<ProjectController>(
builder: (projectController) {
final projectName =
projectController.selectedProject?.name ??
'Select Project';
return MyText.bodySmall(
projectName,
fontWeight: 600,
),
Tooltip(
message: 'Refresh Data',
child: InkWell(
borderRadius: BorderRadius.circular(24),
onTap: () async {
final projectId =
projectController.selectedProjectId?.value;
if (projectId != null) {
try {
await dailyTaskPlaningController
.fetchTaskData(projectId);
} catch (e) {
debugPrint(
'Error refreshing task data: ${e.toString()}');
}
}
},
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.refresh,
color: Colors.green,
size: 28,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: Colors.grey[700],
);
},
),
],
),
),
),
),
body: SafeArea(
child: SingleChildScrollView(
padding: MySpacing.x(0),
child: GetBuilder<DailyTaskPlaningController>(
init: dailyTaskPlaningController,
tag: 'daily_task_planing_controller',
builder: (controller) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MySpacing.height(flexSpacing),
Padding(
padding: MySpacing.x(flexSpacing),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
const SizedBox(width: 8),
MyText.bodyMedium("Refresh", fontWeight: 600),
Tooltip(
message: 'Refresh Data',
child: InkWell(
borderRadius: BorderRadius.circular(24),
onTap: () async {
final projectId =
projectController.selectedProjectId?.value;
if (projectId != null) {
try {
await dailyTaskPlaningController
.fetchTaskData(projectId);
} catch (e) {
debugPrint(
'Error refreshing task data: ${e.toString()}');
}
}
},
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.refresh,
color: Colors.green, size: 28),
),
),
),
),
),
],
),
],
),
),
Padding(
padding: MySpacing.x(flexSpacing),
child: dailyProgressReportTab(),
),
],
);
},
),
Padding(
padding: MySpacing.x(flexSpacing),
child: dailyProgressReportTab(),
),
],
);
},
),
),
),
);
}