timer history added

design_3.0_TM_Module_snagsFix
WaseemAbbasi22 1 month ago
parent 4d2931e335
commit 423968d7f6

@ -63,6 +63,7 @@ class ServiceRequestUtils {
} }
static String formatTimerDuration(int seconds) { static String formatTimerDuration(int seconds) {
int hours = seconds ~/ 3600; int hours = seconds ~/ 3600;
int minutes = (seconds % 3600) ~/ 60; int minutes = (seconds % 3600) ~/ 60;
int remainingSeconds = seconds % 60; int remainingSeconds = seconds % 60;
@ -74,9 +75,11 @@ class ServiceRequestUtils {
if (minutes > 0) { if (minutes > 0) {
formattedDuration += '$minutes minute${minutes > 1 ? 's' : ''} '; formattedDuration += '$minutes minute${minutes > 1 ? 's' : ''} ';
} }
if (remainingSeconds > 0) { if (remainingSeconds > 0) {
formattedDuration += '$remainingSeconds second${remainingSeconds > 1 ? 's' : ''} '; formattedDuration += '$remainingSeconds second${remainingSeconds > 1 ? 's' : ''} ';
} }
if (formattedDuration.isEmpty) { if (formattedDuration.isEmpty) {
formattedDuration = 'Less than a second'; formattedDuration = 'Less than a second';
} }
@ -105,6 +108,33 @@ class ServiceRequestUtils {
return formattedDuration.trim(); return formattedDuration.trim();
} }
static String formatTotalWorkingHours(double timeInHours) {
// Convert hours seconds
int totalSeconds = (timeInHours * 3600).round();
int hours = totalSeconds ~/ 3600;
int minutes = (totalSeconds % 3600) ~/ 60;
int remainingSeconds = totalSeconds % 60;
String formattedDuration = '';
if (hours > 0) {
formattedDuration += '$hours hour${hours > 1 ? 's' : ''} ';
}
if (minutes > 0) {
formattedDuration += '$minutes minute${minutes > 1 ? 's' : ''} ';
}
if (remainingSeconds > 0) {
formattedDuration += '$remainingSeconds second${remainingSeconds > 1 ? 's' : ''} ';
}
if (formattedDuration.isEmpty) {
formattedDuration = 'Less than a minute';
}
return formattedDuration.trim();
}
static void getQrCode({required BuildContext context}) async { static void getQrCode({required BuildContext context}) async {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart';
@ -7,13 +9,14 @@ import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart';
import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
import 'package:test_sa/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_list.dart'; import 'package:test_sa/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_list.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.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/service_request_providers/last_situation_provider.dart'; import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart'; import 'package:test_sa/views/widgets/timer/app_timer.dart';
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
class InternalMaintenanceRequest extends StatefulWidget { class InternalMaintenanceRequest extends StatefulWidget {
static const String id = "/add-internal-activity"; static const String id = "/add-internal-activity";
@ -30,11 +33,14 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
final TextEditingController _workingHoursController = TextEditingController(); final TextEditingController _workingHoursController = TextEditingController();
final TextEditingController _travellingHoursController = TextEditingController(); final TextEditingController _travellingHoursController = TextEditingController();
Lookup statusLookup = Lookup.fromJson({"id": 5619, "name": "New", "value": 1}); Lookup statusLookup = Lookup.fromJson({"id": 5619, "name": "New", "value": 1});
List<TimerHistoryModel> timerList = [];
double totalWorkingHours = 0;
@override @override
void initState() { void initState() {
_requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false); _requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
super.initState(); super.initState();
calculateWorkingTime();
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_travellingHoursController.text = _travellingHoursController.text =
_requestDetailProvider?.activityMaintenanceHelperModel?.travelHours != null ? _requestDetailProvider!.activityMaintenanceHelperModel!.travelHours.toString() : ''; _requestDetailProvider?.activityMaintenanceHelperModel?.travelHours != null ? _requestDetailProvider!.activityMaintenanceHelperModel!.travelHours.toString() : '';
@ -42,6 +48,30 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
// _isLoading = true; // _isLoading = true;
} }
void calculateWorkingTime() {
final helperModel = _requestDetailProvider?.activityMaintenanceHelperModel;
final timers = helperModel?.activityMaintenanceTimers ?? [];
totalWorkingHours = timers.fold<double>(0.0, (sum, item) {
if (item.startTime == null || item.endTime == null) return sum;
try {
final start = DateTime.parse(item.startTime!);
final end = DateTime.parse(item.endTime!);
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.startTime,
endTime: e.endTime,
workingHours: e.workingHours,
);
}).toList();
}
@override @override
void dispose() { void dispose() {
_workingHoursController.dispose(); _workingHoursController.dispose();
@ -52,10 +82,6 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Consumer<ServiceRequestDetailProvider>(builder: (context, requestDetailProvider, child) { return Consumer<ServiceRequestDetailProvider>(builder: (context, requestDetailProvider, child) {
double totalWorkingHours = _requestDetailProvider?.activityMaintenanceHelperModel?.activityMaintenanceTimers
?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endTime!).difference(DateTime.parse(item.startTime!)).inSeconds) ??
0;
bool enableTimer = (requestDetailProvider.lastVisitedRequestActivityId == -1 || requestDetailProvider.activityMaintenanceHelperModel?.id == 0) bool enableTimer = (requestDetailProvider.lastVisitedRequestActivityId == -1 || requestDetailProvider.activityMaintenanceHelperModel?.id == 0)
? true ? true
: requestDetailProvider.activityMaintenanceHelperModel?.id == requestDetailProvider.lastVisitedRequestActivityId; : requestDetailProvider.activityMaintenanceHelperModel?.id == requestDetailProvider.lastVisitedRequestActivityId;
@ -70,19 +96,6 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
// SingleItemDropDownMenu<Lookup, ActivityStatusProvider>(
// context: context,
// height: 56.toScreenHeight,
// title: context.translation.activityStatus,
// showShadow: false,
// backgroundColor: AppColor.neutral100,
// initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus,
// onSelect: (status) {
// print('status i got is ${status?.toJson()}');
// requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status;
// },
// ),
// 8.height,
SingleItemDropDownMenu<Lookup, LastSituationProvider>( SingleItemDropDownMenu<Lookup, LastSituationProvider>(
context: context, context: context,
height: 56.toScreenHeight, height: 56.toScreenHeight,
@ -100,16 +113,6 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
}, },
), ),
8.height, 8.height,
// AppTimerPicker(
// label: context.translation.timer,
// timer: requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker,
// enabled: enableTimer,
// // timerList: requestDetailProvider.activityMaintenanceHelperModel?.timerModelList ?? [],
// onPick: (time) {
// requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker = time;
// },
// ),
// 8.height,
AppTimer( AppTimer(
label: context.translation.timer, label: context.translation.timer,
timer: requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel, timer: requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel,
@ -129,124 +132,14 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
return true; return true;
}, },
), ),
// Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// ADatePicker(
// label: context.translation.startTime,
// hideShadow: true,
// backgroundColor: AppColor.neutral100,
// date: requestDetailProvider.activityMaintenanceHelperModel?.startTime,
// formatDateWithTime: true,
// 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,
// );
// requestDetailProvider.activityMaintenanceHelperModel?.startTime = selectedDateTime;
// requestDetailProvider.activityMaintenanceHelperModel?.endTime = null;
// requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
// _workingHoursController.clear();
// ServiceRequestUtils.calculateAndAssignWorkingHours(
// startTime: requestDetailProvider.activityMaintenanceHelperModel!.startTime,
// endTime: requestDetailProvider.activityMaintenanceHelperModel!.endTime,
// workingHoursController: _workingHoursController,
// updateModel: (hours) {
// requestDetailProvider.activityMaintenanceHelperModel?.workingHour = hours;
// },
// );
// }
// });
// },
// ).expanded,
// 8.width,
// ADatePicker(
// label: context.translation.endTime,
// hideShadow: true,
// backgroundColor: AppColor.neutral100,
// date: requestDetailProvider.activityMaintenanceHelperModel?.endTime,
// formatDateWithTime: true,
// 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);
// if (requestDetailProvider.activityMaintenanceHelperModel!.startTime != null &&
// selectedDateTime.isBefore(requestDetailProvider.activityMaintenanceHelperModel!.startTime!)) {
// "End Date time must be greater then start date".showToast;
// return;
// }
// requestDetailProvider.activityMaintenanceHelperModel?.endTime = selectedDateTime;
// requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
// ServiceRequestUtils.calculateAndAssignWorkingHours(
// startTime: requestDetailProvider.activityMaintenanceHelperModel!.startTime,
// endTime: requestDetailProvider.activityMaintenanceHelperModel!.endTime,
// workingHoursController: _workingHoursController,
// updateModel: (hours) {
// requestDetailProvider.activityMaintenanceHelperModel?.workingHour = hours;
// },
// );
// }
// });
// },
// ).expanded,
// ],
// ),
8.height, 8.height,
if (totalWorkingHours > 0.0) ...[ if (totalWorkingHours > 0.0) ...[
Container( WorkingTimeTile(
height: 56.toScreenHeight, timerList: timerList,
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), totalWorkingTime: totalWorkingHours,
alignment: Alignment.centerLeft,
decoration: BoxDecoration(
color: AppColor.fieldBgColor(context),
borderRadius: BorderRadius.circular(10),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Total Working Time",
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500),
),
Text(
" ${ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round())}",
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
), ),
8.height, 8.height,
], ],
// if (totalWorkingHours > 0.0) ...[
// AppTextFormField(
// labelText: context.translation.workingHours,
// backgroundColor: AppColor.neutral80,
// controller: _workingHoursController,
// suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
// initialValue: requestDetailProvider.activityMaintenanceHelperModel?.workingHour != null ? requestDetailProvider.activityMaintenanceHelperModel?.workingHour.toString() : '',
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// enable: false,
// showShadow: false,
// style: Theme.of(context).textTheme.titleMedium,
// ),
// 8.height,
// ],
AppTextFormField( AppTextFormField(
labelText: context.translation.travelingHours, labelText: context.translation.travelingHours,
controller: _travellingHoursController, controller: _travellingHoursController,
@ -305,7 +198,6 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
}); });
}, },
), ),
// const AssistantEmployeeCard().toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)).paddingOnly(start: 13, end: 14, top: 12),
], ],
), ),
), ),

@ -18,6 +18,7 @@ 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_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
import 'ppm_calibration_tools_form.dart'; import 'ppm_calibration_tools_form.dart';
import 'ppm_external_details_form.dart'; import 'ppm_external_details_form.dart';
@ -43,6 +44,7 @@ class _UpdatePpmState extends State<UpdatePpm> with TickerProviderStateMixin {
TabController? _tabController; TabController? _tabController;
late PpmProvider ppmProvider; late PpmProvider ppmProvider;
_onSubmit({required int status}) async { _onSubmit({required int status}) async {
if (ppmProvider.validate()) { if (ppmProvider.validate()) {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
@ -100,6 +102,8 @@ class _UpdatePpmState extends State<UpdatePpm> with TickerProviderStateMixin {
super.initState(); super.initState();
} }
void initTabs(typeOfService) { void initTabs(typeOfService) {
if (typeOfService == null) { if (typeOfService == null) {
return; return;

@ -24,6 +24,7 @@ import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.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/ppm_asset_availability_provider.dart'; import 'package:test_sa/providers/ppm_asset_availability_provider.dart';
import 'package:test_sa/providers/ppm_electrical_safety_provider.dart'; import 'package:test_sa/providers/ppm_electrical_safety_provider.dart';
import 'package:test_sa/providers/ppm_service_provider.dart'; import 'package:test_sa/providers/ppm_service_provider.dart';
@ -33,6 +34,7 @@ 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/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart'; import 'package:test_sa/views/widgets/timer/app_timer.dart';
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
class WoInfoForm extends StatefulWidget { class WoInfoForm extends StatefulWidget {
// final Ppm model; // final Ppm model;
@ -46,10 +48,14 @@ class WoInfoForm extends StatefulWidget {
} }
class _WoInfoFormState extends State<WoInfoForm> { class _WoInfoFormState extends State<WoInfoForm> {
List<TimerHistoryModel> timerList = [];
double totalWorkingHours = 0;
@override @override
void initState() { void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
PpmProvider ppmProvider = Provider.of<PpmProvider>(context, listen: false); PpmProvider ppmProvider = Provider.of<PpmProvider>(context, listen: false);
calculateWorkingTime();
if (widget.planPreventiveVisit.preventiveVisitAttachments != null && widget.planPreventiveVisit.preventiveVisitAttachments!.isNotEmpty) { if (widget.planPreventiveVisit.preventiveVisitAttachments != null && widget.planPreventiveVisit.preventiveVisitAttachments!.isNotEmpty) {
ppmProvider.ppmPlanAttachments = []; ppmProvider.ppmPlanAttachments = [];
ppmProvider.ppmPlanAttachments.addAll(widget.planPreventiveVisit.preventiveVisitAttachments!.map((e) => GenericAttachmentModel(id: e.id, name: e.attachmentName!)).toList()); ppmProvider.ppmPlanAttachments.addAll(widget.planPreventiveVisit.preventiveVisitAttachments!.map((e) => GenericAttachmentModel(id: e.id, name: e.attachmentName!)).toList());
@ -59,10 +65,35 @@ class _WoInfoFormState extends State<WoInfoForm> {
super.initState(); super.initState();
} }
void calculateWorkingTime() {
final helperModel = widget.planPreventiveVisit;
final timers = helperModel.preventiveVisitTimers ?? [];
totalWorkingHours = timers.fold<double>(0.0, (sum, item) {
if (item.startDateTime == null || item.endDateTime == null) return sum;
try {
final start = DateTime.parse(item.startDateTime!);
final end = DateTime.parse(item.endDateTime!);
final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours
return sum + diffInHours;
} catch (_) {
return sum;
}
});
print('totol working hours ${totalWorkingHours}');
timerList = timers.map((e) {
return TimerHistoryModel(
id: e.id,
startTime: e.startDateTime,
endTime: e.endDateTime,
workingHours: e.workingHours,
);
}).toList();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double totalWorkingHours = // double totalWorkingHours =
widget.planPreventiveVisit.preventiveVisitTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDateTime!).difference(DateTime.parse(item.startDateTime!)).inSeconds) ?? 0; // widget.planPreventiveVisit.preventiveVisitTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDateTime!).difference(DateTime.parse(item.startDateTime!)).inSeconds) ?? 0;
return Consumer<PpmProvider>(builder: (context, ppmProvider, child) { return Consumer<PpmProvider>(builder: (context, ppmProvider, child) {
return ListView( return ListView(
@ -380,14 +411,18 @@ class _WoInfoFormState extends State<WoInfoForm> {
), ),
11.height, 11.height,
if (totalWorkingHours > 0.0) ...[ if (totalWorkingHours > 0.0) ...[
Row( WorkingTimeTile(
crossAxisAlignment: CrossAxisAlignment.center, timerList: timerList,
mainAxisAlignment: MainAxisAlignment.start, totalWorkingTime: totalWorkingHours,
children: [
context.translation.totalWorkingTime.bodyText2(context),
" ${ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round())}".bodyText(context).custom(color: AppColor.black20),
],
), ),
// Row(
// crossAxisAlignment: CrossAxisAlignment.center,
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// context.translation.totalWorkingTime.bodyText2(context),
// " ${ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round())}".bodyText(context).custom(color: AppColor.black20),
// ],
// ),
], ],
// 8.height, // 8.height,
], ],

@ -10,15 +10,55 @@ import 'package:test_sa/models/ppm/recurrent_wo.dart';
import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/working_time_tile.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart'; import 'package:test_sa/views/widgets/timer/app_timer.dart';
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
class RecurrentTaskInfoWidget extends StatelessWidget { class RecurrentTaskInfoWidget extends StatefulWidget {
final RecurrentWoData? model; final RecurrentWoData? model;
RecurrentTaskInfoWidget({super.key, required this.model}); RecurrentTaskInfoWidget({super.key, required this.model});
@override
State<RecurrentTaskInfoWidget> createState() => _RecurrentTaskInfoWidgetState();
}
class _RecurrentTaskInfoWidgetState extends State<RecurrentTaskInfoWidget> {
@override
void initState() {
calculateWorkingTime();
super.initState();
}
List<TimerHistoryModel> timerList = [];
double totalWorkingHours = 0;
void calculateWorkingTime() {
final helperModel = widget.model;
final timers = helperModel?.planRecurrentTaskTimers ?? [];
totalWorkingHours = timers.fold<double>(0.0, (sum, item) {
if (item.startTime == null || item.endTime == null) return sum;
try {
final start = DateTime.parse(item.startTime!);
final end = DateTime.parse(item.endTime!);
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.startTime,
endTime: e.endTime,
workingHours: e.workingHours,
);
}).toList();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
@ -28,41 +68,41 @@ class RecurrentTaskInfoWidget extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (model?.status != null) if (widget.model?.status != null)
StatusLabel( StatusLabel(
label: model?.status?.name, label: widget.model?.status?.name,
textColor: AppColor.getRequestStatusTextColorByName(context, model?.status?.name), textColor: AppColor.getRequestStatusTextColorByName(context, widget.model?.status?.name),
backgroundColor: AppColor.getRequestStatusColorByName(context, model?.status?.name), backgroundColor: AppColor.getRequestStatusColorByName(context, widget.model?.status?.name),
), ),
8.height, 8.height,
model!.title!.bodyText(context).custom(color: AppColor.textColor(context)), widget.model!.title!.bodyText(context).custom(color: AppColor.textColor(context)),
2.height, 2.height,
'${context.translation.taskNo}: ${model!.taskNo!}'.bodyText2(context).custom(color: AppColor.neutral120), '${context.translation.taskNo}: ${widget.model!.taskNo!}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.site}: ${model!.site!.siteName!}'.bodyText2(context).custom(color: AppColor.neutral120), '${context.translation.site}: ${widget.model!.site!.siteName!}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.assignedEmployee}: ${model!.engineer!.userName ?? ""}'.bodyText2(context).custom(color: AppColor.neutral120), '${context.translation.assignedEmployee}: ${widget.model!.engineer!.userName ?? ""}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.scheduledDate}: ${model!.scheduleDate!.toMonthYearFormat}'.bodyText2(context).custom(color: AppColor.neutral120), '${context.translation.scheduledDate}: ${widget.model!.scheduleDate!.toMonthYearFormat}'.bodyText2(context).custom(color: AppColor.neutral120),
], ],
).toShadowContainer(context), ).toShadowContainer(context),
12.height, 12.height,
model!.planRecurrentMedicalTaskRooms!.isEmpty widget.model!.planRecurrentMedicalTaskRooms!.isEmpty
? Column( ? Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
buildingInfoWidget(label: context.translation.department, value: model!.department?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context), buildingInfoWidget(label: context.translation.department, value: widget.model!.department?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context),
8.height, 8.height,
buildingInfoWidget(label: context.translation.floor, value: model!.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context), buildingInfoWidget(label: context.translation.floor, value: widget.model!.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context),
8.height, 8.height,
buildingInfoWidget(label: context.translation.room, value: model!.room?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context), buildingInfoWidget(label: context.translation.room, value: widget.model!.room?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context),
8.height, 8.height,
_timerWidget(context, model!.totalWorkingHours!), _timerWidget(context,totalWorkingHours),
8.height, 8.height,
_commentWidget(context: context, model: model) _commentWidget(context: context, model: widget.model)
], ],
// ], // ],
).toShadowContainer(context, padding: 12) ).toShadowContainer(context, padding: 12)
: Column( : Column(
children: [_timerWidget(context, model!.totalWorkingHours!), 8.height, _commentWidget(context: context, model: model)], children: [_timerWidget(context, totalWorkingHours), 8.height, _commentWidget(context: context, model: widget.model)],
).toShadowContainer(context, padding: 12), ).toShadowContainer(context, padding: 12),
], ],
); );
@ -82,10 +122,10 @@ class RecurrentTaskInfoWidget extends StatelessWidget {
color: AppColor.fieldBgColor(context), color: AppColor.fieldBgColor(context),
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
pickerTimer: model?.recurrentWoTimePicker, pickerTimer: widget.model?.recurrentWoTimePicker,
pickerFromDate: DateTime.tryParse(model?.scheduleDate ?? ''), pickerFromDate: DateTime.tryParse(widget.model?.scheduleDate ?? ''),
onPick: (time) { onPick: (time) {
model?.recurrentWoTimePicker = time; widget.model?.recurrentWoTimePicker = time;
}, },
timerProgress: (isRunning) {}, timerProgress: (isRunning) {},
onChange: (timer) async { onChange: (timer) async {
@ -95,17 +135,9 @@ class RecurrentTaskInfoWidget extends StatelessWidget {
), ),
if (totalWorkingHours > 0.0) ...[ if (totalWorkingHours > 0.0) ...[
12.height, 12.height,
Row( WorkingTimeTile(
crossAxisAlignment: CrossAxisAlignment.center, timerList: timerList,
mainAxisAlignment: MainAxisAlignment.start, totalWorkingTime: totalWorkingHours,
children: [
'Total Working Time:'.bodyText2(context).custom(color: AppColor.neutral120),
8.width,
Text(
ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round()),
style: AppTextStyles.bodyText.copyWith(color: AppColor.textColor(context), fontWeight: FontWeight.w600),
),
],
), ),
], ],
], ],
@ -119,8 +151,8 @@ class RecurrentTaskInfoWidget extends StatelessWidget {
labelText: context.translation.comment, labelText: context.translation.comment,
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
showShadow: false, showShadow: false,
hintStyle: TextStyle(color: context.isDark?AppColor.white10:AppColor.black10), hintStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10),
labelStyle: TextStyle(color: context.isDark?AppColor.white10:AppColor.black10), labelStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10),
alignLabelWithHint: true, alignLabelWithHint: true,
textInputType: TextInputType.multiline, textInputType: TextInputType.multiline,
onChange: (value) { onChange: (value) {

@ -13,6 +13,7 @@ import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.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/loaders/no_data_found.dart';
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
import '../../../../../../controllers/providers/api/all_requests_provider.dart'; import '../../../../../../controllers/providers/api/all_requests_provider.dart';
import 'components/room_tabs_widget.dart'; import 'components/room_tabs_widget.dart';
@ -36,6 +37,7 @@ class _RecurrentWorkOrderViewState extends State<RecurrentWorkOrderView> {
@override @override
void initState() { void initState() {
allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false); allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
// calculateWorkingTime();
Provider.of<AllRequestsProvider>(context, listen: false).getRecurrentWoById(id: widget.taskId!); Provider.of<AllRequestsProvider>(context, listen: false).getRecurrentWoById(id: widget.taskId!);
super.initState(); super.initState();
} }
@ -61,7 +63,7 @@ class _RecurrentWorkOrderViewState extends State<RecurrentWorkOrderView> {
? Column( ? Column(
children: [ children: [
SingleChildScrollView( SingleChildScrollView(
padding: EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -81,14 +83,13 @@ class _RecurrentWorkOrderViewState extends State<RecurrentWorkOrderView> {
if (requestProvider.recurrentWoData?.status?.value != 1) ...[ if (requestProvider.recurrentWoData?.status?.value != 1) ...[
FooterActionButton.footerContainer( FooterActionButton.footerContainer(
context: context, context: context,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
AppFilledButton( AppFilledButton(
label: context.translation.save, label: context.translation.save,
buttonColor: context.isDark?AppColor.neutral20: AppColor.white60, buttonColor: context.isDark ? AppColor.neutral20 : AppColor.white60,
textColor: context.isDark?Colors.white: AppColor.black10, textColor: context.isDark ? Colors.white : AppColor.black10,
onPressed: () => _updateTask(context: context, status: 0), onPressed: () => _updateTask(context: context, status: 0),
).expanded, ).expanded,
12.width, 12.width,

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -27,6 +28,7 @@ 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/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/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/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/gas_request_providers/site_provider.dart';
import 'package:test_sa/providers/loading_list_notifier.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_job_provider.dart';
@ -38,6 +40,7 @@ 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/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/status/report/service_report_assistant_employee_menu.dart';
import 'package:test_sa/views/widgets/timer/app_timer.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/site.dart';
import '../../../models/new_models/work_order_detail_model.dart'; import '../../../models/new_models/work_order_detail_model.dart';
@ -60,6 +63,8 @@ class _UpdateTaskRequestState extends State<UpdateTaskRequest> {
List<TaskJobAttachment> otherAttachments = []; List<TaskJobAttachment> otherAttachments = [];
bool installationType = true; bool installationType = true;
String comments = ''; String comments = '';
List<TimerHistoryModel> timerList = [];
double totalWorkingHours = 0;
@override @override
void initState() { void initState() {
@ -76,12 +81,40 @@ class _UpdateTaskRequestState extends State<UpdateTaskRequest> {
UserProvider _userProvider = Provider.of<UserProvider>(context, listen: false); UserProvider _userProvider = Provider.of<UserProvider>(context, listen: false);
TaskData? taskModel = _taskProvider?.taskRequestModel; TaskData? taskModel = _taskProvider?.taskRequestModel;
_taskProvider?.refresh(); _taskProvider?.refresh();
if (taskModel?.taskJobAttachments != null) { calculateWorkingTime(helperModel: taskModel!);
attachments = taskModel!.taskJobAttachments!.where((e) => e.createdBy == _userProvider.user?.userID).map((e) => GenericAttachmentModel(id: e.id, name: e.name ?? '')).toList(); 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() ?? []; 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<double>(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 @override
void dispose() { void dispose() {
_requestedQuantityController.dispose(); _requestedQuantityController.dispose();
@ -509,8 +542,6 @@ class _UpdateTaskRequestState extends State<UpdateTaskRequest> {
} }
Widget _timerWidget(BuildContext context, bool isTimerEnable, TaskRequestProvider taskProvider) { Widget _timerWidget(BuildContext context, bool isTimerEnable, TaskRequestProvider taskProvider) {
double totalWorkingHours =
taskProvider.taskRequestModel?.taskJobActivityEngineerTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDate!).difference(DateTime.parse(item.startDate!)).inSeconds) ?? 0;
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -535,17 +566,9 @@ class _UpdateTaskRequestState extends State<UpdateTaskRequest> {
), ),
if (totalWorkingHours > 0.0) ...[ if (totalWorkingHours > 0.0) ...[
8.height, 8.height,
Row( WorkingTimeTile(
crossAxisAlignment: CrossAxisAlignment.center, timerList: timerList,
mainAxisAlignment: MainAxisAlignment.start, totalWorkingTime: totalWorkingHours,
children: [
'Total Working Time:'.bodyText2(context).custom(color: AppColor.textColor(context)),
8.width,
Text(
ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round()),
style: AppTextStyles.bodyText.copyWith(color: AppColor.textColor(context), fontWeight: FontWeight.w600),
),
],
), ),
], ],
8.height, 8.height,

@ -0,0 +1,76 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
class WorkingTimeTile extends StatelessWidget {
final List<TimerHistoryModel> timerList;
final double totalWorkingTime;
final String title;
const WorkingTimeTile({
Key? key,
required this.timerList,
required this.totalWorkingTime,
this.title = "Total Working Time",
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
height: 56.toScreenHeight,
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
alignment: Alignment.centerLeft,
decoration: BoxDecoration(
color: AppColor.fieldBgColor(context),
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
)
],
),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Text(
title,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: context.isDark ? null : AppColor.neutral20,
fontWeight: FontWeight.w500,
),
),
Text(
" ${ServiceRequestUtils.formatTotalWorkingHours(totalWorkingTime)}",
style: Theme.of(context).textTheme.bodyMedium,
),
],
).expanded,
8.width,
const Icon(Icons.info_outline_rounded, color: AppColor.primary10),
],
),
).onPress(() async{
await showModalBottomSheet(
context: context,
isDismissible: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
builder: (BuildContext context) =>
TotalWorkingTimeDetailBottomSheet(timerList: timerList),
);
});
}
}

@ -22,11 +22,13 @@ import 'package:test_sa/modules/cm_module/views/components/action_button/footer_
import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart'; import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart';
import 'package:test_sa/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_list.dart'; import 'package:test_sa/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_list.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/working_time_tile.dart';
import 'package:test_sa/views/app_style/sizing.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/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart'; import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart';
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
import '../../../extensions/text_extensions.dart'; import '../../../extensions/text_extensions.dart';
import '../../../models/ppm/ppm.dart'; import '../../../models/ppm/ppm.dart';
@ -53,6 +55,8 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
final DeviceTransfer _formModel = DeviceTransfer(); final DeviceTransfer _formModel = DeviceTransfer();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
List<TimerHistoryModel> timerList = [];
double totalWorkingHours = 0;
List<GenericAttachmentModel> attachments = []; List<GenericAttachmentModel> attachments = [];
@ -200,7 +204,7 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
void initState() { void initState() {
_formModel.fromDetails(widget.model); _formModel.fromDetails(widget.model);
attachments = widget.model.assetTransferAttachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt()??0, name: e.attachmentName!)).toList() ?? []; attachments = widget.model.assetTransferAttachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt()??0, name: e.attachmentName!)).toList() ?? [];
calculateWorkingTime();
super.initState(); super.initState();
} }
@ -210,14 +214,41 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
super.dispose(); super.dispose();
} }
void calculateWorkingTime() {
List<VisitTimers> timers =[];
if(widget.isSender){
timers = widget.model.senderVisitTimers??[];
} else {
timers = widget.model.receiverVisitTimers??[];
}
totalWorkingHours = timers.fold<double>(0.0, (sum, item) {
if (item.startDateTime == null || item.endDateTime == null) return sum;
try {
final start = DateTime.parse(item.startDateTime!);
final end = DateTime.parse(item.endDateTime!);
final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours
return sum + diffInHours;
} catch (_) {
return sum;
}
});
print('total working time is ${totalWorkingHours}');
timerList = timers.map((e) {
return TimerHistoryModel(
id: e.id,
startTime: e.startDateTime,
endTime: e.endDateTime,
workingHours: e.workingHours,
);
}).toList();
}
bool isTimerRunning = false; bool isTimerRunning = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_deviceTransferProvider = Provider.of<DeviceTransferProvider>(context, listen: false); _deviceTransferProvider = Provider.of<DeviceTransferProvider>(context, listen: false);
double totalWorkingHours = widget.isSender
? (widget.model.senderVisitTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDateTime!).difference(DateTime.parse(item.startDateTime!)).inSeconds) ?? 0)
: (widget.model.receiverVisitTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDateTime!).difference(DateTime.parse(item.startDateTime!)).inSeconds) ?? 0);
bool isTimerEnable = widget.isSender ? (!(_formModel.senderMachineStatusValue == 3)) : (!(_formModel.receiverMachineStatusValue == 3)); bool isTimerEnable = widget.isSender ? (!(_formModel.senderMachineStatusValue == 3)) : (!(_formModel.receiverMachineStatusValue == 3));
return Scaffold( return Scaffold(
appBar: DefaultAppBar( appBar: DefaultAppBar(
@ -361,18 +392,22 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
), ),
if (totalWorkingHours > 0.0) ...[ if (totalWorkingHours > 0.0) ...[
12.height, 12.height,
Row( WorkingTimeTile(
crossAxisAlignment: CrossAxisAlignment.center, timerList: timerList,
mainAxisAlignment: MainAxisAlignment.start, totalWorkingTime: totalWorkingHours,
children: [
'Total Working Time:'.bodyText2(context).custom(color: AppColor.neutral120),
8.width,
Text(
ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round()),
style: AppTextStyles.bodyText.copyWith(color: context.isDark?AppColor.white10: AppColor.neutral50, fontWeight: FontWeight.w600),
),
],
), ),
// Row(
// crossAxisAlignment: CrossAxisAlignment.center,
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// 'Total Working Time:'.bodyText2(context).custom(color: AppColor.neutral120),
// 8.width,
// Text(
// ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round()),
// style: AppTextStyles.bodyText.copyWith(color: context.isDark?AppColor.white10: AppColor.neutral50, fontWeight: FontWeight.w600),
// ),
// ],
// ),
], ],
], ],
); );

@ -19,9 +19,11 @@ import 'package:test_sa/modules/cm_module/views/components/action_button/footer_
import 'package:test_sa/new_views/app_style/app_color.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_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/working_time_tile.dart';
import 'package:test_sa/providers/loading_list_notifier.dart'; import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
import '../../../../extensions/text_extensions.dart'; import '../../../../extensions/text_extensions.dart';
import '../../../../models/new_models/gas_refill_model.dart'; import '../../../../models/new_models/gas_refill_model.dart';
@ -58,6 +60,7 @@ class _UpdateGasRefillRequestState extends State<UpdateGasRefillRequest> {
Lookup? _deliveredQuantity; Lookup? _deliveredQuantity;
List<GenericAttachmentModel> _attachments = []; List<GenericAttachmentModel> _attachments = [];
List<TimerHistoryModel> timerList = [];
static List<Lookup> deliveredQuantity = [ static List<Lookup> deliveredQuantity = [
Lookup(name: "1", id: 1, value: 1), Lookup(name: "1", id: 1, value: 1),
@ -74,9 +77,8 @@ class _UpdateGasRefillRequestState extends State<UpdateGasRefillRequest> {
if (widget.gasRefillModel != null) { if (widget.gasRefillModel != null) {
_formModel.fromGasRefillModel(widget.gasRefillModel!); _formModel.fromGasRefillModel(widget.gasRefillModel!);
totalWorkingHours = _formModel.gasRefillTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDate!).difference(DateTime.parse(item.startDate!)).inSeconds) ?? 0;
_commentController.text = _formModel.techComment ?? ""; _commentController.text = _formModel.techComment ?? "";
calculateWorkingTime();
try { try {
_deliveredQuantity = deliveredQuantity.singleWhere((element) => element.value == _formModel.gasRefillDetails![0].deliverdQty); _deliveredQuantity = deliveredQuantity.singleWhere((element) => element.value == _formModel.gasRefillDetails![0].deliverdQty);
_currentDetails.deliverdQty = _deliveredQuantity!.value; _currentDetails.deliverdQty = _deliveredQuantity!.value;
@ -86,7 +88,29 @@ class _UpdateGasRefillRequestState extends State<UpdateGasRefillRequest> {
_attachments.addAll(_formModel.gasRefillAttachments!.map((e) => GenericAttachmentModel(id:e.id,name:e.attachmentName!)).toList()); _attachments.addAll(_formModel.gasRefillAttachments!.map((e) => GenericAttachmentModel(id:e.id,name:e.attachmentName!)).toList());
} }
} }
void calculateWorkingTime() {
final timers = _formModel.gasRefillTimers ?? [];
totalWorkingHours = timers.fold<double>(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.workingHours,
);
}).toList();
}
@override @override
void setState(VoidCallback fn) { void setState(VoidCallback fn) {
if (mounted) super.setState(() {}); if (mounted) super.setState(() {});
@ -204,7 +228,6 @@ class _UpdateGasRefillRequestState extends State<UpdateGasRefillRequest> {
clientName = _userProvider.user?.clientName; clientName = _userProvider.user?.clientName;
} }
} }
double totalWorkingHours = _formModel.gasRefillTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDate!).difference(DateTime.parse(item.startDate!)).inSeconds) ?? 0;
return Scaffold( return Scaffold(
appBar: DefaultAppBar( appBar: DefaultAppBar(
@ -329,17 +352,9 @@ class _UpdateGasRefillRequestState extends State<UpdateGasRefillRequest> {
), ),
if (totalWorkingHours > 0.0) ...[ if (totalWorkingHours > 0.0) ...[
12.height, 12.height,
Row( WorkingTimeTile(
crossAxisAlignment: CrossAxisAlignment.center, timerList: timerList,
mainAxisAlignment: MainAxisAlignment.start, totalWorkingTime: totalWorkingHours,
children: [
'Total Working Time:'.bodyText2(context).custom(color: AppColor.neutral120),
8.width,
Text(
ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round()),
style: AppTextStyles.bodyText.copyWith(color:context.isDark?AppColor.white10: AppColor.neutral50, fontWeight: FontWeight.w600),
),
],
), ),
], ],
], ],

@ -9,75 +9,77 @@ import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
class TotalWorkingTimeDetailBottomSheet extends StatelessWidget { class TotalWorkingTimeDetailBottomSheet extends StatelessWidget {
final List<ActivityMaintenanceTimers> activityMaintenanceTimers; final List<TimerHistoryModel> timerList;
const TotalWorkingTimeDetailBottomSheet({Key? key, this.activityMaintenanceTimers = const []}) : super(key: key); const TotalWorkingTimeDetailBottomSheet({Key? key, this.timerList = const []}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return SafeArea(
height: MediaQuery.of(context).size.height * 0.5, child: Container(
padding: const EdgeInsets.all(16), height: MediaQuery.of(context).size.height * 0.5,
child: Column( padding: const EdgeInsets.all(16),
children: [ child: Column(
Container( children: [
width: 40.toScreenWidth, Container(
height: 5.toScreenHeight, width: 40.toScreenWidth,
decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), height: 5.toScreenHeight,
), decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)),
8.height,
Align(
alignment: AlignmentDirectional.centerStart,
child: Text(
"Total Working Time",
style: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w600, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
), ),
), 8.height,
ListView.separated( Align(
itemCount: activityMaintenanceTimers.length, alignment: AlignmentDirectional.centerStart,
separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), child: Text(
padding: const EdgeInsets.only(top: 16, bottom: 16), "Total Working Time",
itemBuilder: (cxt, index) { style: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w600, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
int totalWorkingHours = DateTime.parse(activityMaintenanceTimers[index].endTime!).difference(DateTime.parse(activityMaintenanceTimers[index].startTime!)).inSeconds; ),
return Column( ),
mainAxisSize: MainAxisSize.min, ListView.separated(
crossAxisAlignment: CrossAxisAlignment.start, itemCount: timerList.length,
children: [ separatorBuilder: (cxt, index) => const Divider().defaultStyle(context),
RichText( padding: const EdgeInsets.only(top: 16, bottom: 16),
text: TextSpan( itemBuilder: (cxt, index) {
text: "From: ", int totalWorkingHours = DateTime.parse(timerList[index].endTime!).difference(DateTime.parse(timerList[index].startTime!)).inSeconds;
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500), return Column(
children: [TextSpan(text: activityMaintenanceTimers[index].startTime!.toServiceRequestDetailsFormat, style: Theme.of(context).textTheme.bodySmall)])), mainAxisSize: MainAxisSize.min,
4.height, crossAxisAlignment: CrossAxisAlignment.start,
RichText( children: [
text: TextSpan( RichText(
text: "To: ", text: TextSpan(
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500), text: "From: ",
children: [TextSpan(text: activityMaintenanceTimers[index].endTime!.toServiceRequestDetailsFormat, style: Theme.of(context).textTheme.bodySmall)])), style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500),
4.height, children: [TextSpan(text: timerList[index].startTime!.toServiceRequestDetailsFormat, style: Theme.of(context).textTheme.bodySmall)])),
RichText( 4.height,
text: TextSpan( RichText(
text: "Duration: ", text: TextSpan(
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500), text: "To: ",
children: [TextSpan(text: " ${ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round())}", style: Theme.of(context).textTheme.bodySmall)])), style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500),
], children: [TextSpan(text: timerList[index].endTime!.toServiceRequestDetailsFormat, style: Theme.of(context).textTheme.bodySmall)])),
); 4.height,
}).expanded, RichText(
], text: TextSpan(
text: "Duration: ",
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500),
children: [TextSpan(text: " ${ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round())}", style: Theme.of(context).textTheme.bodySmall)])),
],
);
}).expanded,
],
),
), ),
); );
} }
} }
class TimerModel { class TimerHistoryModel {
int? id; int? id;
String? startTime; String? startTime;
String? endTime; String? endTime;
dynamic workingHours; dynamic workingHours;
TimerModel({this.id, this.startTime, this.endTime, this.workingHours}); TimerHistoryModel({this.id, this.startTime, this.endTime, this.workingHours});
TimerModel.fromJson(Map<String, dynamic> json) { TimerHistoryModel.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
startTime = json['startTime']; startTime = json['startTime'];
endTime = json['endTime']; endTime = json['endTime'];

Loading…
Cancel
Save