import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/building.dart'; import 'package:test_sa/models/new_models/department.dart'; import 'package:test_sa/models/new_models/floor.dart'; import 'package:test_sa/models/new_models/task_request/task_request_model.dart'; import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; import 'package:test_sa/new_views/common_widgets/working_time_tile.dart'; import 'package:test_sa/providers/gas_request_providers/site_provider.dart'; import 'package:test_sa/providers/loading_list_notifier.dart'; import 'package:test_sa/providers/task_request_provider/task_job_provider.dart'; import 'package:test_sa/providers/task_request_provider/task_request_provider.dart'; import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart'; import 'package:test_sa/views/widgets/timer/app_timer.dart'; import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart'; import '../../../../models/new_models/site.dart'; import '../../../models/new_models/work_order_detail_model.dart'; class UpdateTaskRequest extends StatefulWidget { final int taskId; final String? createdDate; const UpdateTaskRequest({Key? key, required this.taskId, this.createdDate}) : super(key: key); @override State createState() => _UpdateTaskRequestState(); } class _UpdateTaskRequestState extends State { TaskRequestProvider? _taskProvider; final TextEditingController _requestedQuantityController = TextEditingController(); final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); List attachments = []; List otherAttachments = []; bool installationType = true; String comments = ''; List timerList = []; double totalWorkingHours = 0; @override void initState() { WidgetsBinding.instance.addPostFrameCallback((_) { assignData(); }); super.initState(); } Future assignData() async { //may need to pass model in class parameters. _taskProvider = Provider.of(context, listen: false); UserProvider _userProvider = Provider.of(context, listen: false); TaskData? taskModel = _taskProvider?.taskRequestModel; _taskProvider?.refresh(); calculateWorkingTime(helperModel: taskModel!); if (taskModel.taskJobAttachments != null) { attachments = taskModel.taskJobAttachments!.where((e) => e.createdBy == _userProvider.user?.userID).map((e) => GenericAttachmentModel(id: e.id, name: e.name ?? '')).toList(); otherAttachments = taskModel.taskJobAttachments?.where((e) => e.createdBy != _userProvider.user?.userID).toList() ?? []; } } void calculateWorkingTime({required TaskData helperModel}) { //we can make a single timer model for all type of request .... // final helperModel = _taskProvider?.taskRequestModel; final timers = helperModel.taskJobActivityEngineerTimers ?? []; totalWorkingHours = timers.fold(0.0, (sum, item) { if (item.startDate == null || item.endDate == null) return sum; try { final start = DateTime.parse(item.startDate!); final end = DateTime.parse(item.endDate!); final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours return sum + diffInHours; } catch (_) { return sum; } }); timerList = timers.map((e) { return TimerHistoryModel( id: e.id, startTime: e.startDate, endTime: e.endDate, workingHours: e.totalWorkingHour, ); }).toList(); } @override void dispose() { _requestedQuantityController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Consumer(builder: (context, taskProvider, child) { return Scaffold( appBar: DefaultAppBar( title: context.translation.taskRequest, onWillPopScope: () { _updateTask(context: context, status: 0); }, ), key: _scaffoldKey, body: taskProvider.isLoading ? const ALoading() : taskProvider.taskRequestModel != null ? Form( key: _formKey, child: Column( children: [ SingleChildScrollView( padding: EdgeInsets.all(12 * AppStyle.getScaleFactor(context)), child: Column( children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _timerWidget(context, true, taskProvider), 8.height, if (taskProvider.taskRequestModel?.taskType?.isInstallation == true) ...[installationWidget(taskModel: taskProvider.taskRequestModel!)], if (taskProvider.taskRequestModel?.taskType?.isRecallAndAlert == true) ...[ recallAlertTypeWidget(taskModel: taskProvider.taskRequestModel!), ], // if (previousComments.isNotEmpty) ...[ // 'Previous Comments'.bodyText2(context).custom(color: AppColor.neutral50), // 8.height, buildPreviousComments(taskProvider: taskProvider), // 8.height, // ], AppTextFormField( initialValue: "", labelText: context.translation.technicalComment, textInputType: TextInputType.multiline, backgroundColor: AppColor.fieldBgColor(context), labelStyle: TextStyle(color: AppColor.textColor(context)), showShadow: false, alignLabelWithHint: true, onChange: (value) { comments = value; setState(() {}); }, onSaved: (value) {}, ), 20.height, AttachmentPicker( label: context.translation.attachFiles, attachment: attachments, buttonColor: AppColor.black10, onlyImages: false, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), ), ], ).toShadowContainer(context), 16.height, TaskRequestAssistantEmployeeList( assetId: taskProvider.taskRequestModel?.asset?.id, createdDate: widget.createdDate ?? '', //widget.requestDetails?.date assistantEmployeeList: taskProvider.taskRequestModel?.taskJobAssistantEmployees, cardPadding: 0, onListChanged: (updatedList) { setState(() { taskProvider.taskRequestModel?.taskJobAssistantEmployees = updatedList; }); }, ), // const AssistantEmployeeCard().toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)), ], ), ).expanded, FooterActionButton.footerContainer( context: context, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ AppFilledButton( label: context.translation.save, buttonColor: AppColor.white60, textColor: AppColor.black10, onPressed: () => _updateTask(context: context, status: 0), ).expanded, 12.width, AppFilledButton( label: context.translation.complete, buttonColor: AppColor.primary10, onPressed: () => _updateTask(context: context, status: 1), ).expanded, ], ), ), ], ), ) : NoDataFound(message: context.translation.noDataFound).center, ).handlePopScope( cxt: context, onSave: () { _updateTask(context: context, status: 0); }); }); } void _updateTask({required BuildContext context, required int status}) async { TaskRequestProvider taskRequestProvider = Provider.of(context, listen: false); TaskData? taskModel = TaskData.copyWith(taskRequestProvider.taskRequestModel!); taskModel?.statusValue = status; // taskModel.taskTimePicker = taskRequestProvider.taskRequestModel?.taskTimePicker; // taskModel.totalWorkingHours = taskRequestProvider.taskRequestModel?.totalWorkingHours; // taskModel.taskTimerModel = taskRequestProvider.taskRequestModel?.taskTimerModel; // taskModel.timerModelList = taskRequestProvider.taskRequestModel?.timerModelList; if (validate(model: taskModel)) { showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); List taskAttachment = []; if (otherAttachments.isNotEmpty) { taskAttachment.addAll(otherAttachments); } for (var item in attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; taskAttachment.add(TaskJobAttachment(id: item.id, name: fileName)); } taskModel?.taskJobAttachments = taskAttachment; if (taskModel?.taskTimePicker != null) { int durationInSecond = taskModel!.taskTimePicker!.endAt!.difference(taskModel.taskTimePicker!.startAt!).inSeconds; taskModel.taskJobActivityEngineerTimers?.add( TaskJobActivityEngineerTimer( id: 0, startDate: taskModel.taskTimePicker!.startAt!.toIso8601String(), endDate: taskModel.taskTimePicker!.endAt?.toIso8601String(), totalWorkingHour: ((durationInSecond) / 60 / 60), comment: comments, ), ); } taskModel?.timerModelList?.forEach((timer) { int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; taskModel.taskJobActivityEngineerTimers?.add( TaskJobActivityEngineerTimer ( id: 0, startDate: timer.startAt!.toIso8601String(), endDate: timer.endAt?.toIso8601String(), totalWorkingHour: ((durationInSecond) / 60 / 60), comment: timer.comments ?? comments), ); }); await taskRequestProvider.updateTaskByEngineer(taskModel).then((success) async { if (success) { if (status == 1) { AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); allRequestsProvider.reset(); await allRequestsProvider.getAllRequests(context, typeTransaction: taskRequestProvider.taskRequestModel?.taskType?.id); Navigator.pop(context); Navigator.pop(context); Navigator.pop(context); } else { await taskRequestProvider.getTaskById(id: widget.taskId, showLoading: false); Navigator.pop(context); Navigator.pop(context); } } else { Navigator.pop(context); } }); } } Widget installationWidget({required TaskData taskModel}) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ADatePicker( label: context.translation.installationDate, hideShadow: true, backgroundColor: AppColor.fieldBgColor(context), date: DateTime.tryParse(taskModel.installationDate ?? ""), formatDateWithTime: false, onDatePicker: (selectedDate) { showTimePicker( context: context, initialTime: TimeOfDay.now(), ).then((selectedTime) { // Handle the selected date and time here. if (selectedTime != null) { DateTime selectedDateTime = DateTime( selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute, ); taskModel.installationDate = selectedDateTime.toIso8601String(); setState(() {}); } }); }, ), 8.height, AppTextFormField( labelText: context.translation.serialNo, backgroundColor: AppColor.fieldBgColor(context), showShadow: false, labelStyle: AppTextStyles.textFieldLabelStyle, initialValue: taskModel.serialNo ?? '', textInputType: TextInputType.text, onChange: (value) { taskModel.serialNo = value; }, ), 8.height, SingleItemDropDownMenu( context: context, title: 'Installation Site', initialValue: taskModel.site, loading: _taskProvider?.isSiteLoading, showAsBottomSheet: true, backgroundColor: AppColor.fieldBgColor(context), showShadow: false, enabled: false, onSelect: (value) { if (value == null) { return; } taskModel.site = value; taskModel.building = null; taskModel.floor = null; taskModel.department = null; setState(() {}); }, ), 8.height, SingleItemDropDownMenu( context: context, title: 'Installation Building', backgroundColor: AppColor.fieldBgColor(context), showAsBottomSheet: true, loading: _taskProvider?.isSiteLoading, showShadow: false, initialValue: taskModel.building, enabled: taskModel.site?.buildings?.isNotEmpty ?? false, staticData: taskModel.site?.buildings ?? [], onSelect: (value) { if (value == null) { return; } taskModel.building = value; taskModel.floor = null; taskModel.department = null; setState(() {}); }, ), 8.height, SingleItemDropDownMenu( context: context, showAsBottomSheet: true, backgroundColor: AppColor.fieldBgColor(context), loading: _taskProvider?.isSiteLoading, showShadow: false, title: 'Installation Floor', initialValue: taskModel.floor, enabled: taskModel.building?.floors?.isNotEmpty ?? false, staticData: taskModel.building?.floors ?? [], onSelect: (value) { if (value == null) { return; } taskModel.floor = value; taskModel.department = null; setState(() {}); }, ), 8.height, SingleItemDropDownMenu( context: context, title: 'Installation Department', backgroundColor: AppColor.fieldBgColor(context), loading: _taskProvider?.isSiteLoading, showAsBottomSheet: true, showShadow: false, initialValue: taskModel.department, enabled: taskModel.floor?.departments?.isNotEmpty ?? false, staticData: taskModel.floor?.departments ?? [], onSelect: (value) { if (value == null) { return; } taskModel.department = value; taskModel.room = null; setState(() {}); }, ), 8.height, ], ); } Widget recallAlertTypeWidget({required TaskData taskModel}) { Widget userAcknowledgeWidget() { return Row( children: [ InkWell( child: taskModel.isUserAcknowledge == true ? const Icon( Icons.check_box, color: AppColor.primary10, ) : const Icon( Icons.check_box_outline_blank, color: AppColor.neutral120, ), onTap: () { setState(() { taskModel.isUserAcknowledge = !taskModel.isUserAcknowledge!; }); }, ), 6.width, Flexible( child: context.translation.acknowledge.bodyText(context).custom(color: context.isDark ? AppColor.primary50 : AppColor.neutral120), ), ], ); } if (taskModel.typeOfAlert != null) { switch (taskModel.typeOfAlert!.value) { case 1: return userAcknowledgeWidget(); case 2: return Column( children: [ SingleItemDropDownMenu( context: context, height: 56.toScreenHeight, title: context.translation.completedActions, showShadow: false, backgroundColor: AppColor.fieldBgColor(context), enabled: false, showAsBottomSheet: true, initialValue: taskModel.actionNeeded, onSelect: (status) { //read only ... }, ), if (taskModel.actionNeeded?.value == 1) ...[ 8.height, SingleItemDropDownMenu( context: context, height: 56.toScreenHeight, title: context.translation.impactStatus, showShadow: false, backgroundColor: AppColor.fieldBgColor(context), showAsBottomSheet: true, initialValue: taskModel.impactStatus, onSelect: (status) { if (status != null) { taskModel.impactStatus = status; setState(() {}); } }, ), 8.height, ], ], ); case 3: return Column( children: [ userAcknowledgeWidget(), 8.height, SingleItemDropDownMenu( context: context, height: 56.toScreenHeight, title: context.translation.completedActions, showShadow: false, backgroundColor: AppColor.fieldBgColor(context), enabled: false, showAsBottomSheet: true, initialValue: taskModel.actionNeeded, onSelect: (status) { //this is read only ... }, ), 8.height, if (taskModel.actionNeeded?.value == 1) ...[ SingleItemDropDownMenu( context: context, height: 56.toScreenHeight, title: context.translation.impactStatus, showShadow: false, backgroundColor: AppColor.fieldBgColor(context), showAsBottomSheet: true, initialValue: taskModel.impactStatus, onSelect: (status) { if (status != null) { taskModel.impactStatus = status; setState(() {}); } }, ) ], ], ); default: return const SizedBox(); } } return const SizedBox(); } Widget _timerWidget(BuildContext context, bool isTimerEnable, TaskRequestProvider taskProvider) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ AppTimer( label: context.translation.timer, timer: taskProvider.taskRequestModel?.taskTimerModel, pickerFromDate: DateTime.tryParse(widget.createdDate ?? ''), width: double.infinity, enabled: isTimerEnable, decoration: BoxDecoration( color: AppColor.fieldBgColor(context), borderRadius: BorderRadius.circular(10), ), pickerTimer: taskProvider.taskRequestModel?.taskTimePicker, onPick: (time) { taskProvider.taskRequestModel?.taskTimePicker = time; }, onChange: (timer) async { taskProvider.updateTaskTimer(timer: timer); return true; }, ), if (totalWorkingHours > 0.0) ...[ 8.height, WorkingTimeTile( timerList: timerList, totalWorkingTime: totalWorkingHours, ), ], 8.height, ], ); } Widget buildPreviousComments({required TaskRequestProvider taskProvider}) { String previousComments = taskProvider.taskRequestModel?.taskJobActivityEngineerTimers?.map((e) => e.comment?.trim()).where((comment) => comment != null && comment!.isNotEmpty).join('\n') ?? ''; if (previousComments.isNotEmpty) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ 8.height, 'Previous Comments'.bodyText2(context).custom(color: AppColor.neutral50), 8.height, Container( constraints: BoxConstraints( maxHeight: 200.toScreenHeight, ), child: SingleChildScrollView( child: previousComments.bodyText2(context).custom(color: AppColor.neutral50), ), ).toShadowContainer(showShadow: false, context, backgroundColor: AppColor.neutral90, paddingObject: const EdgeInsets.only(left: 10, right: 20, bottom: 20, top: 10)), 8.height, ], ); } return const SizedBox(); } } bool validate({TaskData? model}) { bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; if (isTimerPickerEnable) { if (model?.taskTimerModel?.startAt == null && model?.taskTimePicker == null) { Fluttertoast.showToast(msg: "Working Hours Required"); return false; } if (model?.taskTimePicker == null) { if (model?.taskTimerModel?.startAt == null) { Fluttertoast.showToast(msg: "Working Hours Required"); return false; } if (model?.taskTimerModel?.endAt == null) { Fluttertoast.showToast(msg: "Please Stop The Timer"); return false; } } } else { if (model?.taskTimerModel?.startAt == null) { Fluttertoast.showToast(msg: "Working Hours Required"); return false; } if (model?.taskTimerModel?.endAt == null) { Fluttertoast.showToast(msg: "Please Stop The Timer"); return false; } } if (model!.taskJobAssistantEmployees?.isNotEmpty ?? false) { for (int i = 0; i < model.taskJobAssistantEmployees!.length; i++) { final employee = model.taskJobAssistantEmployees![i]; final position = Utils.getOrdinal(i + 1); if (employee.user == null) { Fluttertoast.showToast( msg: "Please select the $position assistant employee", ); return false; } if (employee.user?.userId != null) { if (employee.startDate == null) { Fluttertoast.showToast( msg: "Please select start time for assistant employee ${employee.user?.userName}", ); return false; } if (employee.endDate == null) { Fluttertoast.showToast( msg: "Please select end time for assistant employee ${employee.user?.userName}", ); return false; } } } } return true; } class TaskRequestAssistantEmployeeList extends StatefulWidget { final List? assistantEmployeeList; final ValueChanged>? onListChanged; final double? cardPadding; final dynamic assetId; final String createdDate; const TaskRequestAssistantEmployeeList({ super.key, this.assistantEmployeeList, this.onListChanged, required this.assetId, this.cardPadding, required this.createdDate, }); @override State createState() => _TaskRequestAssistantEmployeeListState(); } class _TaskRequestAssistantEmployeeListState extends State { late List _list; late List _controllers; @override void initState() { super.initState(); _list = List.from(widget.assistantEmployeeList ?? []); _controllers = _list.map((e) => TextEditingController(text: e.workingHours?.toString() ?? '')).toList(); } void _addNewEntry() { setState(() { _list.add(TaskJobAssistantEmployees()); _controllers.add(TextEditingController()); }); widget.onListChanged?.call(_list); } void _removeEntry(int index) { setState(() { _list.removeAt(index); _controllers.removeAt(index); }); widget.onListChanged?.call(_list); } void _updateModel(int index, void Function(TaskJobAssistantEmployees model) updateList, {bool updateController = false}) { setState(() { updateList(_list[index]); }); } @override Widget build(BuildContext context) { return ListView.builder( itemCount: _list.length + 1, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), padding: EdgeInsets.all(widget.cardPadding ?? 16), itemBuilder: (context, index) { if (index == _list.length) { return AppFilledButton( label: "Add Assistant Employee".addTranslation, maxWidth: true, textColor: AppColor.textColor(context), buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), showIcon: true, onPressed: _addNewEntry, ); } return EmployeeCard( model: _list[index], assetId: widget.assetId, index: index, createdDate: widget.createdDate, // selectedEmployee: selectedEmployee, onUpdate: (updateList) => _updateModel(index, updateList), onRemove: () => _removeEntry(index), workingHoursController: _controllers[index], ); }, ); } } class EmployeeCard extends StatelessWidget { final TaskJobAssistantEmployees model; final int index; final dynamic assetId; final String? createdDate; final void Function(void Function(TaskJobAssistantEmployees model)) onUpdate; final VoidCallback onRemove; final TextEditingController workingHoursController; EmployeeCard({ super.key, required this.model, required this.assetId, required this.index, required this.onUpdate, this.createdDate, required this.onRemove, required this.workingHoursController, }); // AssistantEmployees selectedEmployee = AssistantEmployees(); @override Widget build(BuildContext context) { return Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ context.translation.assistantEmployee.bodyText(context).custom(color: AppColor.textColor(context)), Container( height: 32, width: 32, padding: const EdgeInsets.all(6), child: "trash".toSvgAsset(height: 20, width: 20), ).onPress(onRemove), ], ), 8.height, Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ ServiceReportAssistantEmployeeMenu( title: context.translation.select, backgroundColor: AppColor.fieldBgColor(context), assetId: assetId, initialValue: model.employee, onSelect: (employee) { if (employee != null) { onUpdate((model) { model.employee = employee.copyWith(id: 0); model.user = AssignedEmployee( userId: employee.user?.id, userName: employee.user?.name, ); }); } }, ), 8.height, Row( mainAxisSize: MainAxisSize.min, children: [ ADatePicker( label: context.translation.startTime, hideShadow: true, backgroundColor: AppColor.fieldBgColor(context), date: model.startDate, formatDateWithTime: true, from: DateTime.tryParse(createdDate ?? ''), onDatePicker: (selectedDate) { showTimePicker( context: context, initialTime: TimeOfDay.now(), ).then((selectedTime) { if (selectedTime != null) { final selectedDateTime = DateTime( selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute, ); if (createdDate != null && selectedDateTime.isBefore(DateTime.tryParse(createdDate ?? '')!)) { "Start time is before the request time.".showToast; return; } if (selectedDateTime.isAfter(DateTime.now())) { "Start time is after the current time".showToast; return; } onUpdate((model) { model.startDate = selectedDateTime; CMRequestUtils.calculateAndAssignWorkingHours( startTime: model.startDate, endTime: model.endDate, workingHoursController: workingHoursController, updateModel: (hours) => model.workingHours = hours, ); }); } }); }, ).expanded, 8.width, ADatePicker( label: context.translation.endTime, hideShadow: true, backgroundColor: AppColor.fieldBgColor(context), date: model.endDate, formatDateWithTime: true, from: DateTime.tryParse(createdDate ?? ''), onDatePicker: (selectedDate) { showTimePicker( context: context, initialTime: TimeOfDay.now(), ).then((selectedTime) { if (selectedTime != null) { final endDateTime = DateTime( selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute, ); if (!endDateTime.isBefore(DateTime.now())) { "Please select a time before the current time.".showToast; return; } if (model.startDate == null || !endDateTime.isAfter(model.startDate!)) { "End date must be after start date".showToast; return; } onUpdate((model) { model.endDate = endDateTime; CMRequestUtils.calculateAndAssignWorkingHours( startTime: model.startDate, endTime: model.endDate, workingHoursController: workingHoursController, updateModel: (hours) => model.workingHours = hours, ); }); } }); }, ).expanded, ], ), 8.height, AppTextFormField( labelText: context.translation.workingHours, backgroundColor: AppColor.fieldBgColor(context), controller: workingHoursController, suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), textAlign: TextAlign.center, enable: false, showShadow: false, labelStyle: AppTextStyles.textFieldLabelStyle, style: Theme.of(context).textTheme.titleMedium, ), 8.height, AppTextFormField( initialValue: model.comment, labelText: context.translation.technicalComment, backgroundColor: AppColor.fieldBgColor(context), showShadow: false, labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: context.isDark ? AppColor.white10 : AppColor.black10), alignLabelWithHint: true, textInputType: TextInputType.multiline, onChange: (value) => onUpdate((model) => model.comment = value), // onSaved: (value) => onUpdate((model) => model.technicalComment = value), ), 8.height, ], ) ], ).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16, vertical: 12)).paddingOnly(bottom: 12); } }