|
|
|
|
@ -1,27 +1,33 @@
|
|
|
|
|
import 'dart:convert';
|
|
|
|
|
import 'dart:developer';
|
|
|
|
|
|
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
|
import 'package:test_sa/extensions/context_extension.dart';
|
|
|
|
|
import 'package:test_sa/extensions/enum_extensions.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/models/lookup.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/helper_function.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/models/inspection_person_model.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
|
|
|
|
|
import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.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_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/views/widgets/date_and_time/date_picker.dart';
|
|
|
|
|
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
|
|
|
|
|
import '../../../../new_views/common_widgets/app_filled_button.dart';
|
|
|
|
|
@ -85,12 +91,12 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return Scaffold(
|
|
|
|
|
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
|
|
|
|
appBar: DefaultAppBar(
|
|
|
|
|
title: 'Delivery Inspection'.addTranslation,
|
|
|
|
|
onBackPress: () {
|
|
|
|
|
Navigator.pop(context);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
// appBar: DefaultAppBar(
|
|
|
|
|
// title: 'Delivery Inspection'.addTranslation,
|
|
|
|
|
// onBackPress: () {
|
|
|
|
|
// Navigator.pop(context);
|
|
|
|
|
// },
|
|
|
|
|
// ),
|
|
|
|
|
body: isLoading
|
|
|
|
|
? const CircularProgressIndicator(color: AppColor.primary10).center
|
|
|
|
|
: Form(
|
|
|
|
|
@ -110,9 +116,16 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
|
|
|
|
|
),
|
|
|
|
|
8.height,
|
|
|
|
|
Text(
|
|
|
|
|
model.totalTime != null ? '${model.totalTime.toString()} hours' : '-',
|
|
|
|
|
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
|
|
|
|
|
formatInspectionDuration(model.totalTime),
|
|
|
|
|
style: AppTextStyles.bodyText2.copyWith(
|
|
|
|
|
color: context.isDark ? AppColor.neutral30 : AppColor.neutral120,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
// Text(
|
|
|
|
|
// model.totalTime != null ? '${model.totalTime.toString()} hours' : '-',
|
|
|
|
|
// style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
|
|
|
|
|
// ),
|
|
|
|
|
8.height,
|
|
|
|
|
const Divider().defaultStyle(context),
|
|
|
|
|
Text(
|
|
|
|
|
@ -124,32 +137,50 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
|
|
|
|
|
],
|
|
|
|
|
).toShadowContainer(context, borderRadius: 20, padding: 12))
|
|
|
|
|
.expanded,
|
|
|
|
|
if (!viewOnly) ...[
|
|
|
|
|
FooterActionButton.footerContainer(
|
|
|
|
|
context: context,
|
|
|
|
|
child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap),
|
|
|
|
|
),
|
|
|
|
|
8.height,
|
|
|
|
|
],
|
|
|
|
|
FooterActionButton.footerContainer(
|
|
|
|
|
context: context,
|
|
|
|
|
child: !viewOnly
|
|
|
|
|
? Row(
|
|
|
|
|
? Column(
|
|
|
|
|
children: [
|
|
|
|
|
AppFilledButton(
|
|
|
|
|
label: 'Cancel'.addTranslation,
|
|
|
|
|
maxWidth: true,
|
|
|
|
|
buttonColor: AppColor.background(context),
|
|
|
|
|
// textColor: context.isDark ? AppColor.neutral30 : Colors.white,
|
|
|
|
|
textColor: AppColor.red30,
|
|
|
|
|
showBorder: true,
|
|
|
|
|
onPressed: _cancelTap,
|
|
|
|
|
).expanded,
|
|
|
|
|
12.width,
|
|
|
|
|
AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded,
|
|
|
|
|
buttonColor: AppColor.primary10,
|
|
|
|
|
label: 'Attachments'.addTranslation,
|
|
|
|
|
maxWidth: true,
|
|
|
|
|
onPressed: () {
|
|
|
|
|
HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
|
|
|
|
|
}),
|
|
|
|
|
16.height,
|
|
|
|
|
Row(
|
|
|
|
|
children: [
|
|
|
|
|
AppFilledButton(
|
|
|
|
|
label: 'Cancel'.addTranslation,
|
|
|
|
|
maxWidth: true,
|
|
|
|
|
buttonColor: AppColor.background(context),
|
|
|
|
|
// textColor: context.isDark ? AppColor.neutral30 : Colors.white,
|
|
|
|
|
textColor: AppColor.red30,
|
|
|
|
|
showBorder: true,
|
|
|
|
|
onPressed: _cancelTap,
|
|
|
|
|
).expanded,
|
|
|
|
|
12.width,
|
|
|
|
|
AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded,
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
: AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap),
|
|
|
|
|
: Row(
|
|
|
|
|
children: [
|
|
|
|
|
AppFilledButton(
|
|
|
|
|
buttonColor: AppColor.white60,
|
|
|
|
|
label: 'Attachments'.addTranslation,
|
|
|
|
|
maxWidth: true,
|
|
|
|
|
textColor: AppColor.black10,
|
|
|
|
|
onPressed: () {
|
|
|
|
|
HelperFunction.attachmentTap(context: context, viewOnly: true, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
|
|
|
|
|
}).expanded,
|
|
|
|
|
8.width,
|
|
|
|
|
AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap).expanded,
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
@ -195,69 +226,132 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void calculateTotalTime() {
|
|
|
|
|
if (model.deliveryInspectionInspectedDateFrom == null || model.deliveryInspectionInspectedDateTo == null) {
|
|
|
|
|
final from = model.deliveryInspectionInspectedDateFrom;
|
|
|
|
|
final to = model.deliveryInspectionInspectedDateTo;
|
|
|
|
|
|
|
|
|
|
if (from == null || to == null) {
|
|
|
|
|
model.totalTime = null;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
final fromDate = model.deliveryInspectionInspectedDateFrom!;
|
|
|
|
|
final toDate = model.deliveryInspectionInspectedDateTo!;
|
|
|
|
|
final hours = toDate.difference(fromDate).inSeconds / 3600.0;
|
|
|
|
|
|
|
|
|
|
final diffInSeconds = to.difference(from).inSeconds;
|
|
|
|
|
|
|
|
|
|
if (diffInSeconds < 0) {
|
|
|
|
|
model.totalTime = null;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final hours = diffInSeconds / 3600;
|
|
|
|
|
model.totalTime = num.parse(hours.toStringAsFixed(3));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget inspectionDetailsForm() {
|
|
|
|
|
return Column(
|
|
|
|
|
children: [
|
|
|
|
|
if (widget.requestModel?.isHMG == true) ...[
|
|
|
|
|
OracleUserAutoCompleteField(
|
|
|
|
|
clearAfterPick: false,
|
|
|
|
|
initialValue: model.deliveryInspectionInspectedBy ?? '',
|
|
|
|
|
label: 'Inspected by'.addTranslation,
|
|
|
|
|
onPick: (value) {
|
|
|
|
|
model.deliveryInspectionInspectedBy = value.fullName;
|
|
|
|
|
setState(() {});
|
|
|
|
|
},
|
|
|
|
|
onChanged: (value) {},
|
|
|
|
|
),
|
|
|
|
|
8.height,
|
|
|
|
|
OracleUserAutoCompleteField(
|
|
|
|
|
clearAfterPick: false,
|
|
|
|
|
initialValue: model.deliveryInspectionApprovedBy ?? '',
|
|
|
|
|
label: 'Approved by'.addTranslation,
|
|
|
|
|
onChanged: (value) {},
|
|
|
|
|
onPick: (value) {
|
|
|
|
|
model.deliveryInspectionApprovedBy = value.fullName;
|
|
|
|
|
setState(() {});
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
] //No HMG user free text insted of dropdown ...
|
|
|
|
|
else ...[
|
|
|
|
|
AppTextFormField(
|
|
|
|
|
labelText: 'Inspected by'.addTranslation,
|
|
|
|
|
backgroundColor: AppColor.fieldBgColor(context),
|
|
|
|
|
initialValue: model.deliveryInspectionInspectedBy ?? '',
|
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
|
labelStyle: AppTextStyles.textFieldLabelStyle,
|
|
|
|
|
showShadow: false,
|
|
|
|
|
onChange: (value) {
|
|
|
|
|
model.deliveryInspectionInspectedBy = value;
|
|
|
|
|
},
|
|
|
|
|
style: Theme.of(context).textTheme.titleMedium,
|
|
|
|
|
),
|
|
|
|
|
_inspectionTile(
|
|
|
|
|
title: 'Inspected by'.addTranslation,
|
|
|
|
|
model: model.inspectedByModel,
|
|
|
|
|
isHmg: widget.requestModel?.isHMG == true,
|
|
|
|
|
onTap: () async {
|
|
|
|
|
final result = await showInspectionBottomSheet(
|
|
|
|
|
context,
|
|
|
|
|
title: 'Inspected by'.addTranslation,
|
|
|
|
|
isHmg: widget.requestModel?.isHMG == true,
|
|
|
|
|
initialModel: model.inspectedByModel ?? InspectionPersonModel(),
|
|
|
|
|
);
|
|
|
|
|
if (result != null) {
|
|
|
|
|
setState(() => model.inspectedByModel = result);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
8.height,
|
|
|
|
|
_inspectionTile(
|
|
|
|
|
title: 'Approved by'.addTranslation,
|
|
|
|
|
model: model.approvedByModel,
|
|
|
|
|
isHmg: widget.requestModel?.isHMG == true,
|
|
|
|
|
onTap: () async {
|
|
|
|
|
final result = await showInspectionBottomSheet(
|
|
|
|
|
context,
|
|
|
|
|
title: 'Approved by'.addTranslation,
|
|
|
|
|
isHmg: widget.requestModel?.isHMG == true,
|
|
|
|
|
initialModel: model.approvedByModel ?? InspectionPersonModel(),
|
|
|
|
|
);
|
|
|
|
|
if (result != null) {
|
|
|
|
|
setState(() => model.approvedByModel = result);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
if (widget.requestModel?.paymentTerm?.value == 2) ...[
|
|
|
|
|
8.height,
|
|
|
|
|
AppTextFormField(
|
|
|
|
|
labelText: 'Approved by'.addTranslation,
|
|
|
|
|
backgroundColor: AppColor.fieldBgColor(context),
|
|
|
|
|
initialValue: model.deliveryInspectionApprovedBy ?? '',
|
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
|
labelStyle: AppTextStyles.textFieldLabelStyle,
|
|
|
|
|
showShadow: false,
|
|
|
|
|
onChange: (value) {
|
|
|
|
|
model.deliveryInspectionApprovedBy = value;
|
|
|
|
|
_inspectionTile(
|
|
|
|
|
title: 'Third Approved by'.addTranslation,
|
|
|
|
|
model: model.thirdApprovalModel,
|
|
|
|
|
isHmg: widget.requestModel?.isHMG == true,
|
|
|
|
|
onTap: () async {
|
|
|
|
|
final result = await showInspectionBottomSheet(
|
|
|
|
|
context,
|
|
|
|
|
title: 'Third Approved by'.addTranslation,
|
|
|
|
|
isHmg: widget.requestModel?.isHMG == true,
|
|
|
|
|
initialModel: model.thirdApprovalModel ?? InspectionPersonModel(),
|
|
|
|
|
);
|
|
|
|
|
if (result != null) {
|
|
|
|
|
setState(() => model.thirdApprovalModel = result);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
style: Theme.of(context).textTheme.titleMedium,
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
// if (widget.requestModel?.isHMG == true) ...[
|
|
|
|
|
// OracleUserAutoCompleteField(
|
|
|
|
|
// clearAfterPick: false,
|
|
|
|
|
// initialValue: model.deliveryInspectionInspectedBy ?? '',
|
|
|
|
|
// label: 'Inspected by'.addTranslation,
|
|
|
|
|
// onPick: (value) {
|
|
|
|
|
// model.deliveryInspectionInspectedBy = value.fullName;
|
|
|
|
|
// setState(() {});
|
|
|
|
|
// },
|
|
|
|
|
// onChanged: (value) {},
|
|
|
|
|
// ),
|
|
|
|
|
// 8.height,
|
|
|
|
|
// OracleUserAutoCompleteField(
|
|
|
|
|
// clearAfterPick: false,
|
|
|
|
|
// initialValue: model.deliveryInspectionApprovedBy ?? '',
|
|
|
|
|
// label: 'Approved by'.addTranslation,
|
|
|
|
|
// onChanged: (value) {},
|
|
|
|
|
// onPick: (value) {
|
|
|
|
|
// model.deliveryInspectionApprovedBy = value.fullName;
|
|
|
|
|
// setState(() {});
|
|
|
|
|
// },
|
|
|
|
|
// ),
|
|
|
|
|
// ] //No HMG user free text insted of dropdown ...
|
|
|
|
|
// else ...[
|
|
|
|
|
// AppTextFormField(
|
|
|
|
|
// labelText: 'Inspected by'.addTranslation,
|
|
|
|
|
// backgroundColor: AppColor.fieldBgColor(context),
|
|
|
|
|
// initialValue: model.deliveryInspectionInspectedBy ?? '',
|
|
|
|
|
// textAlign: TextAlign.center,
|
|
|
|
|
// labelStyle: AppTextStyles.textFieldLabelStyle,
|
|
|
|
|
// showShadow: false,
|
|
|
|
|
// onChange: (value) {
|
|
|
|
|
// model.deliveryInspectionInspectedBy = value;
|
|
|
|
|
// },
|
|
|
|
|
// style: Theme.of(context).textTheme.titleMedium,
|
|
|
|
|
// ),
|
|
|
|
|
// 8.height,
|
|
|
|
|
// AppTextFormField(
|
|
|
|
|
// labelText: 'Approved by'.addTranslation,
|
|
|
|
|
// backgroundColor: AppColor.fieldBgColor(context),
|
|
|
|
|
// initialValue: model.deliveryInspectionApprovedBy ?? '',
|
|
|
|
|
// textAlign: TextAlign.center,
|
|
|
|
|
// labelStyle: AppTextStyles.textFieldLabelStyle,
|
|
|
|
|
// showShadow: false,
|
|
|
|
|
// onChange: (value) {
|
|
|
|
|
// model.deliveryInspectionApprovedBy = value;
|
|
|
|
|
// },
|
|
|
|
|
// style: Theme.of(context).textTheme.titleMedium,
|
|
|
|
|
// ),
|
|
|
|
|
// ],
|
|
|
|
|
8.height,
|
|
|
|
|
ADatePicker(
|
|
|
|
|
label: 'Inspected Date/Time From'.addTranslation,
|
|
|
|
|
@ -267,52 +361,31 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
|
|
|
|
|
date: model.deliveryInspectionInspectedDateFrom,
|
|
|
|
|
from: DateTime(DateTime.now().year, 1, 1),
|
|
|
|
|
formatDateWithTime: true,
|
|
|
|
|
onDatePicker: (selectedDate) {
|
|
|
|
|
showTimePicker(
|
|
|
|
|
onDatePicker: (selectedDate) async {
|
|
|
|
|
final selectedTime = await showTimePicker(
|
|
|
|
|
context: context,
|
|
|
|
|
initialTime: TimeOfDay.now(),
|
|
|
|
|
builder: (BuildContext context, Widget? child) {
|
|
|
|
|
final ThemeData currentTheme = Theme.of(context);
|
|
|
|
|
return Theme(
|
|
|
|
|
data: currentTheme.copyWith(
|
|
|
|
|
timePickerTheme: TimePickerThemeData(
|
|
|
|
|
dialHandColor: AppColor.primary10,
|
|
|
|
|
dialBackgroundColor: Colors.grey.withOpacity(0.1),
|
|
|
|
|
hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)),
|
|
|
|
|
dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent),
|
|
|
|
|
dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10),
|
|
|
|
|
dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)),
|
|
|
|
|
entryModeIconColor: AppColor.primary10,
|
|
|
|
|
),
|
|
|
|
|
textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)),
|
|
|
|
|
),
|
|
|
|
|
child: child!,
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
).then((selectedTime) {
|
|
|
|
|
if (selectedTime != null) {
|
|
|
|
|
model.deliveryInspectionInspectedDateFrom = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
|
|
|
|
|
// calculateTotalTime();
|
|
|
|
|
|
|
|
|
|
///need to check if need validation or not.
|
|
|
|
|
// if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) {
|
|
|
|
|
// "Start time is before the request time.".showToast;
|
|
|
|
|
// _pickerStartAt = null;
|
|
|
|
|
// selectedTime = null;
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
if (model.deliveryInspectionInspectedDateFrom!.isAfter(DateTime.now())) {
|
|
|
|
|
"Start time is after than current time".showToast;
|
|
|
|
|
model.deliveryInspectionInspectedDateFrom = null;
|
|
|
|
|
selectedTime = null;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setState(() {});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
builder: _timePickerThemeBuilder,
|
|
|
|
|
);
|
|
|
|
|
if (selectedTime == null) return;
|
|
|
|
|
|
|
|
|
|
final fromDateTime = DateTime(
|
|
|
|
|
selectedDate.year,
|
|
|
|
|
selectedDate.month,
|
|
|
|
|
selectedDate.day,
|
|
|
|
|
selectedTime.hour,
|
|
|
|
|
selectedTime.minute,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!_validateInspectionDates(from: fromDateTime, to: model.deliveryInspectionInspectedDateTo)) {
|
|
|
|
|
return; // invalid, do not assign
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model.deliveryInspectionInspectedDateFrom = fromDateTime;
|
|
|
|
|
setState(() {});
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
8.height,
|
|
|
|
|
ADatePicker(
|
|
|
|
|
label: 'Inspected Date/Time To'.addTranslation,
|
|
|
|
|
@ -322,55 +395,120 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
|
|
|
|
|
date: model.deliveryInspectionInspectedDateTo,
|
|
|
|
|
from: model.deliveryInspectionInspectedDateFrom,
|
|
|
|
|
formatDateWithTime: true,
|
|
|
|
|
onDatePicker: (selectedDate) {
|
|
|
|
|
showTimePicker(
|
|
|
|
|
onDatePicker: (selectedDate) async {
|
|
|
|
|
if (model.deliveryInspectionInspectedDateFrom == null) {
|
|
|
|
|
"Please select time to first".showToast;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final selectedTime = await showTimePicker(
|
|
|
|
|
context: context,
|
|
|
|
|
initialTime: TimeOfDay.now(),
|
|
|
|
|
builder: (BuildContext context, Widget? child) {
|
|
|
|
|
final ThemeData currentTheme = Theme.of(context);
|
|
|
|
|
return Theme(
|
|
|
|
|
data: currentTheme.copyWith(
|
|
|
|
|
timePickerTheme: TimePickerThemeData(
|
|
|
|
|
dialHandColor: AppColor.primary10,
|
|
|
|
|
dialBackgroundColor: Colors.grey.withOpacity(0.1),
|
|
|
|
|
hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)),
|
|
|
|
|
dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent),
|
|
|
|
|
dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10),
|
|
|
|
|
dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)),
|
|
|
|
|
entryModeIconColor: AppColor.primary10,
|
|
|
|
|
),
|
|
|
|
|
textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)),
|
|
|
|
|
),
|
|
|
|
|
child: child!,
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
).then((selectedTime) {
|
|
|
|
|
if (selectedTime != null) {
|
|
|
|
|
model.deliveryInspectionInspectedDateTo = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
|
|
|
|
|
calculateTotalTime();
|
|
|
|
|
|
|
|
|
|
///Need to check need validation or not..
|
|
|
|
|
// if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) {
|
|
|
|
|
// "Start time is before the request time.".showToast;
|
|
|
|
|
// _pickerStartAt = null;
|
|
|
|
|
// selectedTime = null;
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
if (model.deliveryInspectionInspectedDateTo!.isAfter(DateTime.now())) {
|
|
|
|
|
"End time is after than current time".showToast;
|
|
|
|
|
model.deliveryInspectionInspectedDateTo = null;
|
|
|
|
|
selectedTime = null;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
setState(() {});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
builder: _timePickerThemeBuilder,
|
|
|
|
|
);
|
|
|
|
|
if (selectedTime == null) return;
|
|
|
|
|
|
|
|
|
|
final toDateTime = DateTime(
|
|
|
|
|
selectedDate.year,
|
|
|
|
|
selectedDate.month,
|
|
|
|
|
selectedDate.day,
|
|
|
|
|
selectedTime.hour,
|
|
|
|
|
selectedTime.minute,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!_validateInspectionDates(from: model.deliveryInspectionInspectedDateFrom, to: toDateTime)) {
|
|
|
|
|
return; // invalid, do not assign
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model.deliveryInspectionInspectedDateTo = toDateTime;
|
|
|
|
|
setState(() {});
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool _validateInspectionDates({DateTime? from, DateTime? to}) {
|
|
|
|
|
if (from == null && to == null) return true;
|
|
|
|
|
if (from != null) {
|
|
|
|
|
if (from.isAfter(DateTime.now())) {
|
|
|
|
|
"Time From cannot be in the future".showToast;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (to != null && from.isAfter(to)) {
|
|
|
|
|
"Time To cannot be after Time From".showToast;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (to != null) {
|
|
|
|
|
if (to.isAfter(DateTime.now())) {
|
|
|
|
|
"Time To cannot be in the future".showToast;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (from != null && to.isBefore(from)) {
|
|
|
|
|
"Timer To cannot be before from time".showToast;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (from != null && to != null) {
|
|
|
|
|
final diffInSeconds = to.difference(from).inSeconds;
|
|
|
|
|
if (diffInSeconds < 0) {
|
|
|
|
|
model.totalTime = null;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
final hours = diffInSeconds / 3600.0;
|
|
|
|
|
model.totalTime = num.parse(hours.toStringAsFixed(3));
|
|
|
|
|
} else {
|
|
|
|
|
model.totalTime = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String formatInspectionDuration(num? hours) {
|
|
|
|
|
if (hours == null) return '-';
|
|
|
|
|
|
|
|
|
|
if (hours < 1) {
|
|
|
|
|
final minutes = (hours * 60).round();
|
|
|
|
|
return '$minutes minutes';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return '${hours.toStringAsFixed(2)} hours';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _timePickerThemeBuilder(BuildContext context, Widget? child) {
|
|
|
|
|
final ThemeData currentTheme = Theme.of(context);
|
|
|
|
|
|
|
|
|
|
return Theme(
|
|
|
|
|
data: currentTheme.copyWith(
|
|
|
|
|
timePickerTheme: TimePickerThemeData(
|
|
|
|
|
dialHandColor: AppColor.primary10,
|
|
|
|
|
dialBackgroundColor: Colors.grey.withOpacity(0.1),
|
|
|
|
|
hourMinuteColor: MaterialStateColor.resolveWith(
|
|
|
|
|
(states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1),
|
|
|
|
|
),
|
|
|
|
|
dayPeriodColor: MaterialStateColor.resolveWith(
|
|
|
|
|
(states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent,
|
|
|
|
|
),
|
|
|
|
|
dayPeriodTextColor: MaterialStateColor.resolveWith(
|
|
|
|
|
(states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10,
|
|
|
|
|
),
|
|
|
|
|
dayPeriodBorderSide: BorderSide(
|
|
|
|
|
color: Colors.grey.withOpacity(0.2),
|
|
|
|
|
),
|
|
|
|
|
entryModeIconColor: AppColor.primary10,
|
|
|
|
|
),
|
|
|
|
|
textButtonTheme: TextButtonThemeData(
|
|
|
|
|
style: TextButton.styleFrom(
|
|
|
|
|
foregroundColor: AppColor.primary10,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
child: child!,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget inspectionDetails() {
|
|
|
|
|
return Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
@ -418,13 +556,69 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _attachmentTap() async {
|
|
|
|
|
Navigator.push(
|
|
|
|
|
context,
|
|
|
|
|
MaterialPageRoute(
|
|
|
|
|
builder: (context) => AssetDeliveryAttachmentView(
|
|
|
|
|
tableItemId: widget.deliveryTableModel.id,
|
|
|
|
|
)));
|
|
|
|
|
Widget _inspectionTile({
|
|
|
|
|
required String title,
|
|
|
|
|
InspectionPersonModel? model,
|
|
|
|
|
required bool isHmg,
|
|
|
|
|
required VoidCallback onTap,
|
|
|
|
|
}) {
|
|
|
|
|
return InkWell(
|
|
|
|
|
onTap: onTap,
|
|
|
|
|
borderRadius: BorderRadius.circular(12),
|
|
|
|
|
child: Container(
|
|
|
|
|
padding: const EdgeInsets.all(14),
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: AppColor.fieldBgColor(context),
|
|
|
|
|
borderRadius: BorderRadius.circular(12),
|
|
|
|
|
),
|
|
|
|
|
child: Row(
|
|
|
|
|
children: [
|
|
|
|
|
Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
Text(title, style: AppTextStyles.textFieldLabelStyle),
|
|
|
|
|
6.height,
|
|
|
|
|
Row(
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
|
children: [
|
|
|
|
|
Text(
|
|
|
|
|
model?.name?.isNotEmpty == true ? model!.name! : 'Tap to add'.addTranslation,
|
|
|
|
|
style: AppTextStyles.bodyText,
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
///Need to display other info as well
|
|
|
|
|
// Text(
|
|
|
|
|
// model?.email?.isNotEmpty == true
|
|
|
|
|
// ? model!.email!
|
|
|
|
|
// : '',
|
|
|
|
|
// style: AppTextStyles.bodyText,
|
|
|
|
|
// ),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<Lookup?> showAttachmentTypePicker() {
|
|
|
|
|
return showDialog<Lookup>(
|
|
|
|
|
context: context,
|
|
|
|
|
builder: (_) {
|
|
|
|
|
return AlertDialog(
|
|
|
|
|
content: SingleItemDropDownMenu<Lookup, AttachmentTypeLookupProvider>(
|
|
|
|
|
context: context,
|
|
|
|
|
title: context.translation.reason,
|
|
|
|
|
showAsFullScreenDialog: false,
|
|
|
|
|
onSelect: (value) {
|
|
|
|
|
Navigator.pop(context, value);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _cancelTap() async {
|
|
|
|
|
@ -440,21 +634,44 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
|
|
|
|
|
|
|
|
|
|
void _nextTap() {
|
|
|
|
|
if (widget.deliveryTableModel.isContainsTechnicalInspection == true) {
|
|
|
|
|
// Navigator.push(
|
|
|
|
|
// context,
|
|
|
|
|
// MaterialPageRoute(
|
|
|
|
|
// builder: (context) => TechnicalInspectionLinesListView(
|
|
|
|
|
// deliveryTableModel: widget.deliveryTableModel,
|
|
|
|
|
// requestModel: widget.requestModel,
|
|
|
|
|
// ))
|
|
|
|
|
// );
|
|
|
|
|
Navigator.push(
|
|
|
|
|
context,
|
|
|
|
|
MaterialPageRoute(
|
|
|
|
|
builder: (context) => TechnicalInspectionLinesListView(
|
|
|
|
|
deliveryTableModel: widget.deliveryTableModel,
|
|
|
|
|
requestModel: widget.requestModel,
|
|
|
|
|
builder: (context) => AssetDeliveryStageTabPage(
|
|
|
|
|
title: 'Technical Inspection'.addTranslation,
|
|
|
|
|
detailWidget: TechnicalInspectionLinesListView(
|
|
|
|
|
deliveryTableModel: widget.deliveryTableModel,
|
|
|
|
|
requestModel: widget.requestModel,
|
|
|
|
|
),
|
|
|
|
|
tableId: widget.deliveryTableModel.id,
|
|
|
|
|
)));
|
|
|
|
|
} else {
|
|
|
|
|
Navigator.push(
|
|
|
|
|
context,
|
|
|
|
|
MaterialPageRoute(
|
|
|
|
|
builder: (context) => EndUserCostCenterLIstView(
|
|
|
|
|
deliveryTableModel: widget.deliveryTableModel,
|
|
|
|
|
requestModel: widget.requestModel,
|
|
|
|
|
builder: (context) => AssetDeliveryStageTabPage(
|
|
|
|
|
title: 'End-User Acceptance'.addTranslation,
|
|
|
|
|
detailWidget: EndUserCostCenterLIstView(
|
|
|
|
|
deliveryTableModel: widget.deliveryTableModel,
|
|
|
|
|
requestModel: widget.requestModel,
|
|
|
|
|
),
|
|
|
|
|
tableId: widget.deliveryTableModel.id,
|
|
|
|
|
)));
|
|
|
|
|
// Navigator.push(
|
|
|
|
|
// context,
|
|
|
|
|
// MaterialPageRoute(
|
|
|
|
|
// builder: (context) => EndUserCostCenterLIstView(
|
|
|
|
|
// deliveryTableModel: widget.deliveryTableModel,
|
|
|
|
|
// requestModel: widget.requestModel,
|
|
|
|
|
// )));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -470,4 +687,40 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<InspectionPersonModel?> showInspectionBottomSheet(
|
|
|
|
|
BuildContext context, {
|
|
|
|
|
required String title,
|
|
|
|
|
required bool isHmg,
|
|
|
|
|
required InspectionPersonModel initialModel,
|
|
|
|
|
}) {
|
|
|
|
|
return showModalBottomSheet<InspectionPersonModel>(
|
|
|
|
|
context: context,
|
|
|
|
|
isScrollControlled: true,
|
|
|
|
|
shape: const RoundedRectangleBorder(
|
|
|
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
|
|
|
|
),
|
|
|
|
|
builder: (_) {
|
|
|
|
|
if (initialModel.localSignature == null && initialModel.signature != null) {
|
|
|
|
|
initialModel.localSignature = signatureFromString(initialModel.signature);
|
|
|
|
|
}
|
|
|
|
|
return InspectionPersonBottomSheet(
|
|
|
|
|
title: title,
|
|
|
|
|
isHmg: isHmg,
|
|
|
|
|
model: InspectionPersonModel(
|
|
|
|
|
name: initialModel.name,
|
|
|
|
|
email: initialModel.email,
|
|
|
|
|
signature: initialModel.signature,
|
|
|
|
|
localSignature: initialModel.localSignature,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Uint8List? signatureFromString(String? value) {
|
|
|
|
|
if (value == null || !value.contains('|')) return null;
|
|
|
|
|
final base64Part = value.split('|').last;
|
|
|
|
|
return base64Decode(base64Part);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|