onufitness_mobile/lib/screens/goals/widgets/input_goal_bottom_sheet.dart
2026-01-13 11:36:24 +05:30

889 lines
32 KiB
Dart

// import 'package:flutter/material.dart';
// import 'package:flutter_screenutil/flutter_screenutil.dart';
// import 'package:get/get.dart';
// import 'package:onufitness/constants/color_constant.dart';
// import 'package:onufitness/constants/text_constant.dart';
// import 'package:onufitness/screens/goals/controllers/goal_controller.dart';
// import 'package:onufitness/screens/goals/models/get_all_goals_response_model.dart';
// import 'package:onufitness/utils/custom_sneakbar.dart';
// import 'package:onufitness/widgets/Buttons/custom_submit_button.dart';
// class PerformanceInputBottomSheet extends StatefulWidget {
// final List<Task> tasks;
// const PerformanceInputBottomSheet({super.key, required this.tasks});
// @override
// State<PerformanceInputBottomSheet> createState() =>
// _PerformanceInputBottomSheetState();
// }
// class _PerformanceInputBottomSheetState
// extends State<PerformanceInputBottomSheet> {
// final goalController = Get.find<GoalController>();
// final _formKey = GlobalKey<FormState>();
// Task? currentlySelectedTaskFromDropdown;
// List<Task> uniqueTasks = [];
// @override
// void initState() {
// super.initState();
// initializeUniqueTasks();
// resetForm();
// }
// void initializeUniqueTasks() {
// // Remove duplicates and create unique list
// Set<int> seenTaskIds = <int>{};
// uniqueTasks.clear();
// for (final task in widget.tasks) {
// if (task.goalTaskId != null && !seenTaskIds.contains(task.goalTaskId)) {
// uniqueTasks.add(task);
// seenTaskIds.add(task.goalTaskId!);
// }
// }
// }
// void resetForm() {
// currentlySelectedTaskFromDropdown = null;
// goalController.clearForm();
// }
// bool validateForm() {
// if (!_formKey.currentState!.validate()) {
// return false;
// }
// if (currentlySelectedTaskFromDropdown == null) {
// customSnackbar(
// title: "Empty Field",
// message: "Please select a task",
// duration: 2,
// );
// return false;
// }
// if (goalController.selectedDate.value == null) {
// customSnackbar(
// title: 'Empty Field',
// message: 'Please select a date',
// duration: 2,
// );
// return false;
// }
// if (goalController.valueController.text.trim().isEmpty) {
// customSnackbar(
// title: 'Empty Field',
// message: 'Please enter a value',
// duration: 2,
// );
// return false;
// }
// final value = double.tryParse(goalController.valueController.text.trim());
// if (value == null || value <= 0) {
// customSnackbar(
// title: 'Empty Field',
// message: 'Please enter a valid positive number',
// duration: 2,
// );
// return false;
// }
// return true;
// }
// Future<void> handleSubmit() async {
// if (!validateForm()) {
// return;
// }
// try {
// final success = await goalController.inputGoalTask();
// if (success) {
// goalController.fetchAllJoinedGoals(isRefresh: true);
// if (mounted) {
// Future.delayed(Duration(milliseconds: 500), () {
// Get.back();
// });
// }
// }
// } catch (e) {
// customSnackbar(
// title: 'Error',
// message: 'Something went wrong. Please try again.',
// duration: 2,
// );
// }
// }
// @override
// Widget build(BuildContext context) {
// return Container(
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius: BorderRadius.vertical(top: Radius.circular(20.r)),
// ),
// child: Padding(
// padding: EdgeInsets.all(20.sp),
// child: Form(
// key: _formKey,
// child: SingleChildScrollView(
// child: Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Center(
// child: Container(
// height: 4.h,
// width: 40.w,
// decoration: BoxDecoration(
// color: Color(darkGreyColor),
// borderRadius: BorderRadius.circular(2.r),
// ),
// ),
// ),
// SizedBox(height: 20.h),
// Text(
// 'Input Your Performance',
// style: TextStyle(
// fontSize: largeSizeText,
// fontWeight: FontWeight.bold,
// color: Colors.black,
// ),
// ),
// SizedBox(height: 24.h),
// GestureDetector(
// onTap: () => goalController.selectDate(context),
// child: Container(
// width: double.infinity,
// padding: EdgeInsets.symmetric(
// horizontal: 16.w,
// vertical: 16.h,
// ),
// decoration: BoxDecoration(
// color: textFieldFillColor,
// borderRadius: BorderRadius.circular(12.r),
// border: Border.all(
// color:
// goalController.selectedDate.value == null
// ? Colors.red.withValues(alpha: 0.3)
// : lightGreyColor,
// ),
// ),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Obx(
// () => Text(
// goalController.showSelectedDateToUI.value.isEmpty
// ? 'Select Date'
// : goalController.showSelectedDateToUI.value,
// style: TextStyle(
// fontSize: regularSizeText,
// color:
// goalController
// .showSelectedDateToUI
// .value
// .isEmpty
// ? Color(darkGreyColor)
// : Colors.black,
// ),
// ),
// ),
// Icon(
// Icons.calendar_today,
// color: Color(darkGreyColor),
// size: 20.sp,
// ),
// ],
// ),
// ),
// ),
// SizedBox(height: 20.h),
// Container(
// width: double.infinity,
// padding: EdgeInsets.symmetric(
// horizontal: 16.w,
// vertical: 4.h,
// ),
// decoration: BoxDecoration(
// color: textFieldFillColor,
// borderRadius: BorderRadius.circular(12.r),
// border: Border.all(
// color:
// currentlySelectedTaskFromDropdown == null
// ? Colors.red.withValues(alpha: 0.3)
// : lightGreyColor,
// ),
// ),
// child: DropdownButtonHideUnderline(
// child: DropdownButton<Task>(
// isExpanded: true,
// value: currentlySelectedTaskFromDropdown,
// hint: Text(
// 'Select Task',
// style: TextStyle(
// fontSize: regularSizeText,
// color: Color(darkGreyColor),
// ),
// ),
// icon: Icon(
// Icons.keyboard_arrow_down,
// color: Color(darkGreyColor),
// size: 24.sp,
// ),
// style: TextStyle(
// fontSize: regularSizeText,
// color: Colors.black,
// ),
// items:
// uniqueTasks.map((Task task) {
// return DropdownMenuItem<Task>(
// value: task,
// // child: Column(
// // crossAxisAlignment: CrossAxisAlignment.start,
// // mainAxisSize: MainAxisSize.min,
// // children: [
// // Text(
// // task.taskTitle ?? 'Untitled Task',
// // style: TextStyle(
// // fontSize: regularSizeText,
// // color: Colors.black,
// // fontWeight: FontWeight.w400,
// // ),
// // ),
// // ],
// // ),
// child: Text(
// task.taskTitle ?? 'Untitled Task',
// style: TextStyle(
// fontSize: regularSizeText,
// color: Colors.black,
// fontWeight: FontWeight.w400,
// ),
// ),
// );
// }).toList(),
// onChanged: (Task? newValue) {
// if (newValue != null) {
// setState(() {
// currentlySelectedTaskFromDropdown = newValue;
// });
// goalController.updateSelectedTask(newValue);
// }
// },
// dropdownColor: Colors.white,
// borderRadius: BorderRadius.circular(12.r),
// ),
// ),
// ),
// SizedBox(height: 20.h),
// Container(
// width: double.infinity,
// padding: EdgeInsets.symmetric(
// horizontal: 16.w,
// vertical: 16.h,
// ),
// decoration: BoxDecoration(
// color: textFieldFillColor,
// borderRadius: BorderRadius.circular(12.r),
// border: Border.all(color: lightGreyColor),
// ),
// child: Text(
// currentlySelectedTaskFromDropdown?.taskUnit ?? 'Unit',
// style: TextStyle(
// fontSize: regularSizeText,
// color:
// currentlySelectedTaskFromDropdown == null
// ? Color(darkGreyColor)
// : Colors.black,
// ),
// ),
// ),
// SizedBox(height: 20.h),
// Container(
// width: double.infinity,
// decoration: BoxDecoration(
// color: textFieldFillColor,
// borderRadius: BorderRadius.circular(12.r),
// border: Border.all(color: lightGreyColor),
// ),
// child: TextFormField(
// controller: goalController.valueController,
// keyboardType: TextInputType.numberWithOptions(
// decimal: true,
// ),
// style: TextStyle(
// fontSize: regularSizeText,
// color: Colors.black,
// ),
// decoration: InputDecoration(
// hintText: 'Enter value',
// hintStyle: TextStyle(
// color: Color(darkGreyColor),
// fontSize: regularSizeText,
// ),
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(
// horizontal: 16.w,
// vertical: 16.h,
// ),
// ),
// validator: (value) {
// if (value == null || value.trim().isEmpty) {
// return 'Please enter a value';
// }
// final numValue = double.tryParse(value.trim());
// if (numValue == null || numValue <= 0) {
// return 'Please enter a valid positive number';
// }
// return null;
// },
// ),
// ),
// SizedBox(height: 32.h),
// Obx(
// () => CustomSubmitButton(
// isLoading: goalController.isInputLoading.value,
// text: "Submit",
// onPressed: handleSubmit,
// ),
// ),
// ],
// ),
// ),
// ),
// ),
// );
// }
// }
//.......Above one is with Task Dropdown, Below one is with Task BottomSheet.......................................................................................
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:onufitness/constants/color_constant.dart';
import 'package:onufitness/constants/text_constant.dart';
import 'package:onufitness/screens/goals/controllers/goal_controller.dart';
import 'package:onufitness/screens/goals/models/get_all_goals_response_model.dart';
import 'package:onufitness/utils/custom_sneakbar.dart';
import 'package:onufitness/widgets/Buttons/custom_submit_button.dart';
class PerformanceInputBottomSheet extends StatefulWidget {
final List<Task> tasks;
const PerformanceInputBottomSheet({super.key, required this.tasks});
@override
State<PerformanceInputBottomSheet> createState() =>
_PerformanceInputBottomSheetState();
}
class _PerformanceInputBottomSheetState
extends State<PerformanceInputBottomSheet> {
final goalController = Get.find<GoalController>();
final _formKey = GlobalKey<FormState>();
Task? selectedTask;
late List<Task> uniqueTasks;
@override
void initState() {
super.initState();
_initializeData();
}
void _initializeData() {
final seenIds = <int>{};
uniqueTasks =
widget.tasks
.where(
(task) =>
task.goalTaskId != null && seenIds.add(task.goalTaskId!),
)
.toList();
goalController.clearForm();
}
bool _validateAndShowError() {
if (!_formKey.currentState!.validate()) return false;
final validations = [
(selectedTask == null, "Please select a task"),
(goalController.selectedDate.value == null, "Please select a date"),
(
goalController.valueController.text.trim().isEmpty,
"Please enter a value",
),
];
for (final (condition, message) in validations) {
if (condition) {
customSnackbar(title: "Empty Field", message: message, duration: 2);
return false;
}
}
return true;
}
Future<void> _handleSubmit() async {
if (!_validateAndShowError()) return;
try {
if (await goalController.inputGoalTask()) {
goalController.fetchAllJoinedGoals(isRefresh: true);
if (mounted) Future.delayed(500.milliseconds, Get.back);
}
} catch (e) {
customSnackbar(
title: 'Error',
message: 'Something went wrong. Please try again.',
duration: 2,
);
}
}
Widget _buildDropdownField() {
return GestureDetector(
onTap: () => _showTaskPicker(),
child: Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h),
decoration: BoxDecoration(
color: textFieldFillColor,
borderRadius: BorderRadius.circular(12.r),
border: Border.all(
color:
selectedTask == null
? Colors.red.withValues(alpha: 0.3)
: lightGreyColor,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
selectedTask?.taskTitle ?? 'Select Task',
style: TextStyle(
fontSize: regularSizeText,
color:
selectedTask == null
? Color(darkGreyColor)
: Colors.black,
),
overflow: TextOverflow.ellipsis,
),
),
Icon(
Icons.keyboard_arrow_down,
color: Color(darkGreyColor),
size: 24.sp,
),
],
),
),
);
}
Widget _buildRadioButton({required bool isSelected}) {
return Container(
width: 20.sp,
height: 20.sp,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color:
isSelected
? Theme.of(context).primaryColor
: Color(darkGreyColor).withValues(alpha: 0.4),
width: 2.0,
),
color: Colors.white,
),
child:
isSelected
? Center(
child: Container(
width: 10.sp,
height: 10.sp,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).primaryColor,
),
),
)
: null,
);
}
void _showTaskPicker() {
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
isScrollControlled: true,
useSafeArea: false,
builder:
(context) => Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.6,
minHeight: 250.h,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(24.r)),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.1),
blurRadius: 10,
offset: Offset(0, -5),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Handle
Container(
margin: EdgeInsets.only(top: 12.h),
height: 4.h,
width: 40.w,
decoration: BoxDecoration(
color: Color(darkGreyColor).withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(2.r),
),
),
// Header
Container(
padding: EdgeInsets.symmetric(
horizontal: 20.w,
vertical: 20.h,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Select Task',
style: TextStyle(
fontSize: largeSizeText,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
GestureDetector(
onTap: () => Navigator.pop(context),
child: Container(
padding: EdgeInsets.all(8.sp),
decoration: BoxDecoration(
color: Color(darkGreyColor).withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(20.r),
),
child: Icon(
Icons.close,
size: 20.sp,
color: Color(darkGreyColor),
),
),
),
],
),
),
// Divider
Container(
height: 1,
color: Color(darkGreyColor).withValues(alpha: 0.1),
),
// Task List
Flexible(
child: ListView.separated(
padding: EdgeInsets.symmetric(vertical: 8.h),
itemCount: uniqueTasks.length,
separatorBuilder:
(context, index) => Container(
height: 1,
margin: EdgeInsets.symmetric(horizontal: 20.w),
color: Color(darkGreyColor).withValues(alpha: 0.05),
),
itemBuilder: (context, index) {
final task = uniqueTasks[index];
final isSelected =
selectedTask?.goalTaskId == task.goalTaskId;
return InkWell(
onTap: () {
setState(() => selectedTask = task);
goalController.updateSelectedTask(task);
Navigator.pop(context);
},
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 20.w,
vertical: 16.h,
),
color:
isSelected
? Theme.of(
context,
).primaryColor.withValues(alpha: 0.05)
: Colors.transparent,
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
task.taskTitle ?? 'Untitled Task',
style: TextStyle(
fontSize: regularSizeText,
fontWeight:
isSelected
? FontWeight.w600
: FontWeight.w400,
color:
isSelected
? Theme.of(context).primaryColor
: Colors.black,
),
),
if (task.taskUnit?.isNotEmpty == true) ...[
SizedBox(height: 4.h),
Text(
'Unit: ${task.taskUnit}',
style: TextStyle(
fontSize: smallSizeText,
color: Color(darkGreyColor),
),
),
],
],
),
),
SizedBox(width: 12.w),
_buildRadioButton(isSelected: isSelected),
],
),
),
);
},
),
),
],
),
),
);
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.9,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(20.r)),
),
child: Padding(
padding: EdgeInsets.all(20.sp),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Handle
Center(
child: Container(
height: 4.h,
width: 40.w,
decoration: BoxDecoration(
color: Color(darkGreyColor),
borderRadius: BorderRadius.circular(2.r),
),
),
),
SizedBox(height: 20.h),
// Title
Text(
'Input Your Performance',
style: TextStyle(
fontSize: largeSizeText,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 24.h),
// Date Selector
GestureDetector(
onTap: () => goalController.selectDate(context),
child: Container(
width: double.infinity,
padding: EdgeInsets.symmetric(
horizontal: 16.w,
vertical: 16.h,
),
decoration: BoxDecoration(
color: textFieldFillColor,
borderRadius: BorderRadius.circular(12.r),
border: Border.all(
color:
goalController.selectedDate.value == null
? Colors.red.withValues(alpha: 0.3)
: lightGreyColor,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Obx(
() => Text(
goalController
.showSelectedDateToUI
.value
.isEmpty
? 'Select Date'
: goalController.showSelectedDateToUI.value,
style: TextStyle(
fontSize: regularSizeText,
color:
goalController
.showSelectedDateToUI
.value
.isEmpty
? Color(darkGreyColor)
: Colors.black,
),
),
),
Icon(
Icons.calendar_today,
color: Color(darkGreyColor),
size: 20.sp,
),
],
),
),
),
SizedBox(height: 20.h),
// Task Dropdown (Custom)
_buildDropdownField(),
SizedBox(height: 20.h),
// Unit Display
Container(
width: double.infinity,
padding: EdgeInsets.symmetric(
horizontal: 16.w,
vertical: 16.h,
),
decoration: BoxDecoration(
color: textFieldFillColor,
borderRadius: BorderRadius.circular(12.r),
border: Border.all(color: lightGreyColor),
),
child: Text(
selectedTask?.taskUnit ?? 'Unit',
style: TextStyle(
fontSize: regularSizeText,
color:
selectedTask == null
? Color(darkGreyColor)
: Colors.black,
),
),
),
SizedBox(height: 20.h),
// Value Input
TextFormField(
controller: goalController.valueController,
keyboardType: const TextInputType.numberWithOptions(
decimal: true,
),
style: TextStyle(
fontSize: regularSizeText,
color: Colors.black,
),
decoration: InputDecoration(
hintText: 'Enter value',
hintStyle: TextStyle(
color: Color(darkGreyColor),
fontSize: regularSizeText,
),
filled: true,
fillColor: textFieldFillColor,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.r),
borderSide: BorderSide(color: lightGreyColor),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.r),
borderSide: BorderSide(color: lightGreyColor),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 16.w,
vertical: 16.h,
),
),
validator: (value) {
if (value?.trim().isEmpty ?? true) {
return 'Please enter a value';
}
if (double.tryParse(value!.trim()) == null ||
double.parse(value.trim()) <= 0) {
return 'Please enter a valid positive number';
}
return null;
},
),
SizedBox(height: 32.h),
// Submit Button
Obx(
() => CustomSubmitButton(
isLoading: goalController.isInputLoading.value,
text: "Submit",
onPressed: _handleSubmit,
),
),
],
),
),
),
),
),
Container(
padding: EdgeInsetsDirectional.only(
bottom: MediaQuery.of(context).viewPadding.bottom,
),
color: Colors.white,
),
],
);
}
}