From e5775019a4a6a8c99779132dc0c0ff89b90b0bf0 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Sun, 5 Oct 2025 15:32:09 +0300 Subject: [PATCH] asset inventory design --- lib/app_strings/app_asset.dart | 4 +- .../autocomplete_generic_field.dart | 144 ++++++ lib/controllers/api_routes/urls.dart | 12 +- .../providers/api/all_requests_provider.dart | 2 +- .../widgets/request_category_list.dart | 5 + lib/main.dart | 2 + .../models/session_model.dart | 225 +++++++++ .../pages/asset_detail_card_view.dart | 95 ++++ .../pages/asset_inventory_detail_view.dart | 163 +++++++ .../pages/asset_inventory_form_view.dart | 426 ++++++++++++++++++ .../pages/asset_inventory_page.dart | 116 +++++ .../asset_inventory_scan_assets_view.dart | 53 +++ .../pages/inventory_seession_card.dart | 133 ++++++ .../pages/pick_site_information_view.dart | 225 +++++++++ .../provider/asset_inventory_provider.dart | 62 +++ .../land_page/contact_us_bottom_sheet.dart | 4 +- .../my_request/my_requests_page.dart | 4 +- .../requests/request_paginated_listview.dart | 62 +-- .../widgets/request_item_view_list.dart | 6 +- lib/views/widgets/equipment/asset_picker.dart | 13 +- pubspec.lock | 8 + 21 files changed, 1712 insertions(+), 52 deletions(-) create mode 100644 lib/common_widgets/autocomplete_generic_field.dart create mode 100644 lib/modules/asset_inventory_module/models/session_model.dart create mode 100644 lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart create mode 100644 lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart create mode 100644 lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart create mode 100644 lib/modules/asset_inventory_module/pages/asset_inventory_page.dart create mode 100644 lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart create mode 100644 lib/modules/asset_inventory_module/pages/inventory_seession_card.dart create mode 100644 lib/modules/asset_inventory_module/pages/pick_site_information_view.dart create mode 100644 lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart diff --git a/lib/app_strings/app_asset.dart b/lib/app_strings/app_asset.dart index 242f0170..b5d64cea 100644 --- a/lib/app_strings/app_asset.dart +++ b/lib/app_strings/app_asset.dart @@ -10,7 +10,7 @@ class AppAsset { static String maintenanceIcon = 'maintenance_icon'; static String retiredAssetIcon = 'assets/images/retired_asset_icon.svg'; static String sparePartIcon = 'spare_part_icon'; - static String editIcon = 'assets/images/edit_icon.svg'; - static String deleteIcon = 'assets/images/delete_icon.svg'; + static String editIcon = 'assets/images/edit_icon'; + static String deleteIcon = 'assets/images/delete_icon'; static String overDueIcon = 'assets/images/overdue.svg'; } diff --git a/lib/common_widgets/autocomplete_generic_field.dart b/lib/common_widgets/autocomplete_generic_field.dart new file mode 100644 index 00000000..b812efe8 --- /dev/null +++ b/lib/common_widgets/autocomplete_generic_field.dart @@ -0,0 +1,144 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; + +class AutoCompleteGenericField extends StatefulWidget { + final String? label; + final String initialValue; + final bool clearAfterPick; + final Future> Function(String query) onSearch; + final String Function(T item) displayString; + final Function(T item) onPick; + + const AutoCompleteGenericField({ + Key? key, + this.label, + required this.initialValue, + required this.onSearch, + required this.displayString, + required this.onPick, + this.clearAfterPick = true, + }) : super(key: key); + + @override + State> createState() => _AutoCompleteGenericFieldState(); +} + +class _AutoCompleteGenericFieldState extends State> { + late TextEditingController _controller; + List _options = []; + bool _isLoading = false; + + @override + void initState() { + _controller = TextEditingController(text: widget.initialValue); + super.initState(); + } + + @override + void didUpdateWidget(covariant AutoCompleteGenericField oldWidget) { + if (widget.initialValue != oldWidget.initialValue) { + _controller.text = widget.initialValue; + } + super.didUpdateWidget(oldWidget); + } + + Future _search(String query) async { + if (query.isEmpty) { + setState(() => _options = []); + return; + } + setState(() => _isLoading = true); + try { + final results = await widget.onSearch(query); + setState(() => _options = results); + } finally { + setState(() => _isLoading = false); + } + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10)); + + return Container( + decoration: BoxDecoration( + color: AppColor.background(context), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + ), + child: RawAutocomplete( + // textEditingController: _controller, + optionsBuilder: (TextEditingValue textEditingValue) => _options, + displayStringForOption: widget.displayString, + fieldViewBuilder: (context, fieldTextEditingController, fieldFocusNode, onFieldSubmitted) { + return TextField( + controller: _controller, + focusNode: fieldFocusNode, + style: AppTextStyles.bodyText.copyWith(color: AppColor.black10), + textAlign: TextAlign.start, + decoration: InputDecoration( + border: border, + disabledBorder: border, + focusedBorder: border, + enabledBorder: border, + errorBorder: border, + contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth), + // suffixIcon: _isLoading + // ? const Padding( + // padding: EdgeInsets.all(8.0), + // child: SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2)), + // ) + // : const Icon(Icons.search, size: 18), + filled: true, + fillColor: AppColor.fieldBgColor(context), + labelText: widget.label, + labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)), + ), + textInputAction: TextInputAction.search, + onChanged: (text) => _search(text), + onSubmitted: (_) => onFieldSubmitted(), + ); + }, + onSelected: (T selection) { + if (widget.clearAfterPick) { + _controller.clear(); + } else { + _controller.text = widget.displayString(selection); + } + widget.onPick(selection); + }, + optionsViewBuilder: (context, onSelected, options) { + return Align( + alignment: Alignment.topLeft, + child: Material( + elevation: 4, + borderRadius: BorderRadius.circular(10), + child: ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 200, minWidth: 200), + child: ListView.builder( + padding: EdgeInsets.zero, + itemCount: options.length, + itemBuilder: (context, index) { + final option = options.elementAt(index); + return ListTile( + title: Text(widget.displayString(option)), + onTap: () => onSelected(option), + ); + }, + ), + ), + ), + ); + }, + ), + ); + } +} diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 2cac62b1..26bc7b04 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,12 +4,12 @@ class URLs { static const String appReleaseBuildNumber = "26"; // static const host1 = "https://atomsm.hmg.com"; // production url - // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static String _baseUrl = "$_host/mobile"; - // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis - static final String _baseUrl = "$_host/mobile"; // host local UAT + static final String _baseUrl = "$_host/v3/mobile"; // new V3 apis + // static final String _baseUrl = "$_host/mobile"; // host local UAT // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM static String _host = host1; @@ -295,4 +295,8 @@ class URLs { static get addComment => "$_baseUrl/CallRequest/AddHistoryComment"; // add static get getSiteContactInfo => "$_baseUrl/AssetGroupSiteContactInfo"; // add + +// asset inventory Urls. + static get getAssetInventoryById => '$_baseUrl/AssetInventory/GetAssetInventoryById'; +// AssetInventory/GetAssetInventoryById } diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index 54fd7776..f95ef38d 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -143,7 +143,7 @@ class AllRequestsProvider extends ChangeNotifier { } final type = typeTransaction == null ? search?.typeTransaction == null || (search?.typeTransaction?.isEmpty ?? false) - ? [1, 2, 3, 4, 5, 6,7] + ? [1, 2, 3, 4, 5, 6,7,8] : search!.typeTransaction : [typeTransaction]; List status = (search?.statuses == null || (search?.statuses?.isEmpty ?? false)) ? (((search?.isArchived ?? false) ? [3] : [1, 2, 4])) : search!.statuses!; diff --git a/lib/dashboard_latest/widgets/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart index 5c6fe481..9247fdbb 100644 --- a/lib/dashboard_latest/widgets/request_category_list.dart +++ b/lib/dashboard_latest/widgets/request_category_list.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/inventory_seession_card.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; @@ -48,6 +49,10 @@ class RequestCategoryList extends StatelessWidget { return RecurrentWoItemView(requestData: request); case 6: return TaskRequestItemView(requestData: request); + case 7: + return TaskRequestItemView(requestData: request); + case 8: + return InventorySessionCard(requestData: request); default: return Container( height: 100, diff --git a/lib/main.dart b/lib/main.dart index e60fb1e8..d9fabe55 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -25,6 +25,7 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_last_calls_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_types_provider.dart'; +import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart'; @@ -280,6 +281,7 @@ class MyApp extends StatelessWidget { //ChangeNotifierProvider(create: (_) => RequestStatusProvider()), ChangeNotifierProvider(create: (_) => VendorProvider()), ChangeNotifierProvider(create: (_) => PpmChecklistStatusProvider()), + ChangeNotifierProvider(create: (_) => AssetInventoryProvider()), ], child: GestureDetector( onTap: () { diff --git a/lib/modules/asset_inventory_module/models/session_model.dart b/lib/modules/asset_inventory_module/models/session_model.dart new file mode 100644 index 00000000..1860d02d --- /dev/null +++ b/lib/modules/asset_inventory_module/models/session_model.dart @@ -0,0 +1,225 @@ + +class SessionModel { + int? id; + String? sessionName; + int? sessionTypeId; + String? sessionTypeName; + int? statusId; + String? statusName; + String? startDate; + String? endDate; + List assetInventorySites = []; + List assetInventoryAssignedEmployee = []; + + SessionModel({ + this.id, + this.sessionName, + this.sessionTypeId, + this.sessionTypeName, + this.statusId, + this.statusName, + this.startDate, + this.endDate, + List? assetInventorySites, + List? assetInventoryAssignedEmployee, + }) { + this.assetInventorySites = assetInventorySites ?? []; + this.assetInventoryAssignedEmployee = assetInventoryAssignedEmployee ?? []; + } + + SessionModel.fromJson(Map json) { + id = json['id']; + sessionName = json['sessionName']; + sessionTypeId = json['sessionTypeId']; + sessionTypeName = json['sessionTypeName']; + statusId = json['statusId']; + statusName = json['statusName']; + startDate = json['startDate']; + endDate = json['endDate']; + + if (json['assetInventorySites'] != null) { + assetInventorySites = (json['assetInventorySites'] as List).map((e) => AssetInventorySite.fromJson(e)).toList(); + } + + if (json['assetInventoryAssignedEmployee'] != null) { + assetInventoryAssignedEmployee = (json['assetInventoryAssignedEmployee'] as List).map((e) => AssetInventoryAssignedEmployee.fromJson(e)).toList(); + } + } + + Map toJson() { + final map = {}; + map['id'] = id; + map['sessionName'] = sessionName; + map['sessionTypeId'] = sessionTypeId; + map['sessionTypeName'] = sessionTypeName; + map['statusId'] = statusId; + map['statusName'] = statusName; + map['startDate'] = startDate; + map['endDate'] = endDate; + map['assetInventorySites'] = assetInventorySites.map((e) => e.toJson()).toList(); + map['assetInventoryAssignedEmployee'] = assetInventoryAssignedEmployee.map((e) => e.toJson()).toList(); + return map; + } +} + +class AssetInventorySite { + int? siteId; + String? siteName; + List assetInventoryBuildings = []; + + AssetInventorySite({ + this.siteId, + this.siteName, + List? assetInventoryBuildings, + }) { + this.assetInventoryBuildings = assetInventoryBuildings ?? []; + } + + AssetInventorySite.fromJson(Map json) { + siteId = json['siteId']; + siteName = json['siteName']; + + if (json['assetInventoryBuildings'] != null) { + assetInventoryBuildings = (json['assetInventoryBuildings'] as List).map((e) => AssetInventoryBuilding.fromJson(e)).toList(); + } + } + + Map toJson() { + final map = {}; + map['siteId'] = siteId; + map['siteName'] = siteName; + map['assetInventoryBuildings'] = assetInventoryBuildings.map((e) => e.toJson()).toList(); + return map; + } +} + +class AssetInventoryBuilding { + int? buildingId; + String? buildingName; + List assetInventoryFloors = []; + + AssetInventoryBuilding({ + this.buildingId, + this.buildingName, + List? assetInventoryFloors, + }) { + this.assetInventoryFloors = assetInventoryFloors ?? []; + } + + AssetInventoryBuilding.fromJson(Map json) { + buildingId = json['buildingId']; + buildingName = json['buildingName']; + + if (json['assetInventoryFloors'] != null) { + assetInventoryFloors = (json['assetInventoryFloors'] as List).map((e) => AssetInventoryFloor.fromJson(e)).toList(); + } + } + + Map toJson() { + final map = {}; + map['buildingId'] = buildingId; + map['buildingName'] = buildingName; + map['assetInventoryFloors'] = assetInventoryFloors.map((e) => e.toJson()).toList(); + return map; + } +} + +class AssetInventoryFloor { + int? floorId; + String? floorName; + List assetInventoryDepartments = []; + + AssetInventoryFloor({ + this.floorId, + this.floorName, + List? assetInventoryDepartments, + }) { + this.assetInventoryDepartments = assetInventoryDepartments ?? []; + } + + AssetInventoryFloor.fromJson(Map json) { + floorId = json['floorId']; + floorName = json['floorName']; + + if (json['assetInventoryDepartments'] != null) { + assetInventoryDepartments = (json['assetInventoryDepartments'] as List).map((e) => AssetInventoryDepartment.fromJson(e)).toList(); + } + } + + Map toJson() { + final map = {}; + map['floorId'] = floorId; + map['floorName'] = floorName; + map['assetInventoryDepartments'] = assetInventoryDepartments.map((e) => e.toJson()).toList(); + return map; + } +} + +class AssetInventoryDepartment { + int? departmentId; + String? departmentName; + List assetInventoryRooms = []; + + AssetInventoryDepartment({ + this.departmentId, + this.departmentName, + List? assetInventoryRooms, + }) { + this.assetInventoryRooms = assetInventoryRooms ?? []; + } + + AssetInventoryDepartment.fromJson(Map json) { + departmentId = json['departmentId']; + departmentName = json['departmentName']; + + if (json['assetInventoryRooms'] != null) { + assetInventoryRooms = (json['assetInventoryRooms'] as List).map((e) => AssetInventoryRoom.fromJson(e)).toList(); + } + } + + Map toJson() { + final map = {}; + map['departmentId'] = departmentId; + map['departmentName'] = departmentName; + map['assetInventoryRooms'] = assetInventoryRooms.map((e) => e.toJson()).toList(); + return map; + } +} + +class AssetInventoryRoom { + int? roomId; + String? roomName; + + AssetInventoryRoom({this.roomId, this.roomName}); + + AssetInventoryRoom.fromJson(Map json) { + roomId = json['roomId']; + roomName = json['roomName']; + } + + Map toJson() { + final map = {}; + map['roomId'] = roomId; + map['roomName'] = roomName; + return map; + } +} + +class AssetInventoryAssignedEmployee { + String? assignedEngineerId; + String? assignedEngineerName; + + AssetInventoryAssignedEmployee({this.assignedEngineerId, this.assignedEngineerName}); + + AssetInventoryAssignedEmployee.fromJson(Map json) { + assignedEngineerId = json['assignedEngineerId']; + assignedEngineerName = json['assignedEngineerName']; + } + + Map toJson() { + final map = {}; + map['assignedEngineerId'] = assignedEngineerId; + map['assignedEngineerName'] = assignedEngineerName; + return map; + } +} diff --git a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart new file mode 100644 index 00000000..a77a6f6a --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart @@ -0,0 +1,95 @@ +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/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/new_models/work_order_detail_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class AssetDetailCardView extends StatelessWidget { + WorkOrderData workOrder; + + AssetDetailCardView({super.key,required this.workOrder}); + + @override + Widget build(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: workOrder.priority?.name, + id: workOrder.priority!.id!, + radius: 4, + textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!), + backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!), + ), + 8.height, + Text( + context.translation.assetInformation, + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + // 8.height, + Text( + '${context.translation.serialNo}: ${workOrder.workOrderContactPerson[0].name ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.manufacture}: ${workOrder.workOrderContactPerson[0].name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.model}: ${workOrder.workOrderContactPerson[0].name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.site}: ${workOrder.workOrderContactPerson[0].name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.department}: ${workOrder.workOrderContactPerson[0].name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ),Text( + '${context.translation.supplier}: ${workOrder.workOrderContactPerson[0].name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ),Text( + '${'Remarks'.addTranslation}: ${workOrder.workOrderContactPerson[0].name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 'edit_icon'.toSvgAsset().onPress((){ + //Handle edit... + }), + 20.width, + 'delete_icon'.toSvgAsset().onPress((){ + //handle delete.. + }) + ], + ), + 20.height, + Container( + height: 100, + width:100, + color: Colors.red, + child: 'edit_icon'.toSvgAsset().center, + ) + + ],) + ], + ).toShadowContainer(context); + } +} diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart new file mode 100644 index 00000000..a805f1b1 --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart @@ -0,0 +1,163 @@ +import 'package:flutter/material.dart'; +import 'package:provider/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/models/new_models/work_order_detail_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; +import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class AssetInventoryDetailView extends StatefulWidget { + SessionModel sessionModel; + + AssetInventoryDetailView({Key? key, required this.sessionModel}) : super(key: key); + + @override + State createState() => _AssetInventoryDetailViewState(); +} + +class _AssetInventoryDetailViewState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + //TODO remove this provider and loading obj as well don't need here ... + return Consumer(builder: (pContext, requestProvider, _) { + return requestProvider.isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : requestProvider.currentWorkOrder == null + ? const NoDataFound() + : Column( + children: [ + SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + requestDetailCard(context, requestProvider.currentWorkOrder!.data!), + 12.height, + siteListCard(context, requestProvider.currentWorkOrder!.data!), + // 20.height, + ], + ), + ).expanded, + ], + ); + }); + } + + + + TextStyle infoTextStyle(context) => AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120); + + Widget requestDetailCard(BuildContext context, WorkOrderData workOrder) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Wrap( + runSpacing: 8, + children: [ + StatusLabel( + label: workOrder.priority?.name, + id: workOrder.priority!.id!, + radius: 4, + textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!), + backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!), + ), + 8.width, + StatusLabel( + radius: 4, + label: workOrder.status!.name, + textColor: AppColor.getHistoryLogStatusTextColorByName(workOrder.status!.name!), + backgroundColor: AppColor.getHistoryLogStatusColorByName(workOrder.status!.name!), + ), + ], + ).expanded, + Text( + workOrder.requestedDate!.toString().toServiceRequestCardFormat, + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ) + ], + ), + 8.height, + Text( + context.translation.requestDetails, + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 8.height, + Text( + '${'Session Name'.addTranslation}: ${workOrder.assetNdModel!.name?.cleanupWhitespace.capitalizeFirstOfEach}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + + // 8.height, + Text( + '${'Session Typ'.addTranslation}: ${workOrder.asset!.assetNumber}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${'Start Date:'.addTranslation}: ${workOrder.asset!.assetSerialNo}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${'End Date:'.addTranslation}: ${workOrder.asset!.assetSerialNo}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ).paddingOnly(start: 16, end: 16, top: 16, bottom: 8).toShadowContainer(context, padding: 0); + } + + Widget siteListCard(BuildContext context, WorkOrderData workOrder) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.separated( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '${workOrder.workOrderContactPerson[0].name ?? '-'}', + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + Text( + '${context.translation.building}: ${workOrder.workOrderContactPerson[0].employeeId ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.floor}: ${workOrder.workOrderContactPerson[0].mobilePhone ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.department} ${workOrder.workOrderContactPerson[0].position ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.room}: ${workOrder.workOrderContactPerson[0].email ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ), + separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), + itemCount: 4), + ], + ).toShadowContainer(context, padding: 12); + } +} diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart new file mode 100644 index 00000000..dc2c6736 --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart @@ -0,0 +1,426 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/common_widgets/autocomplete_generic_field.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart'; +import 'package:test_sa/dashboard_latest/dashboard_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/models/device/asset.dart'; +import 'package:test_sa/models/device/asset_transfer_attachment.dart'; +import 'package:test_sa/models/device/device_transfer.dart'; +import 'package:test_sa/models/enums/user_types.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/new_models/department.dart'; +import 'package:test_sa/models/new_models/floor.dart'; +import 'package:test_sa/models/service_request/pending_service_request_model.dart'; +import 'package:test_sa/models/service_request/spare_parts.dart'; +import 'package:test_sa/models/service_request/supplier_details.dart'; +import 'package:test_sa/modules/cm_module/utilities/service_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_text_form_field.dart'; +import 'package:test_sa/providers/ppm_service_provider.dart'; +import 'package:test_sa/providers/work_order/vendor_provider.dart'; +import 'package:test_sa/views/pages/user/requests/pending_requests_screen.dart'; +import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; +import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +import '../../../models/new_models/building.dart'; +import '../../../models/new_models/site.dart'; +import '../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../new_views/common_widgets/default_app_bar.dart'; +import '../../../new_views/common_widgets/single_item_drop_down_menu.dart'; +import '../../../providers/gas_request_providers/site_provider.dart'; +import '../../../providers/loading_list_notifier.dart'; + +class AssetInventoryFormView extends StatefulWidget { + static const String id = "/request-device-transfer"; + + const AssetInventoryFormView({Key? key}) : super(key: key); + + @override + State createState() => _AssetInventoryFormViewState(); +} + +class _AssetInventoryFormViewState extends State { + //TODO Need to replace with provider and models we have ... + late DeviceTransferProvider _deviceTransferProvider; + final DeviceTransfer _transferModel = DeviceTransfer(id: 0); + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + Asset _assetDestination = Asset(); + Asset? _pickedAsset; + final List attachments = []; + + void _onSubmit() async { + _transferModel.assetId = _pickedAsset?.id; + _transferModel.destSiteId = _assetDestination.site?.id; + _transferModel.destBuildingId = _assetDestination.building?.id; + _transferModel.destFloorId = _assetDestination.floor?.id; + _transferModel.destDepartmentId = _assetDestination.department?.id; + _transferModel.destRoomId = _assetDestination.room?.id; + + if (!_formKey.currentState!.validate() || !(await validateRequest())) { + return; + } + _formKey.currentState!.save(); + List attachement = []; + for (var item in attachments) { + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + attachement.add(AssetTransferAttachment(id: item.id, attachmentName: fileName)); + } + _transferModel.attachments = attachement; + + await _deviceTransferProvider.createRequest( + context: context, + model: _transferModel, + ); + if (_deviceTransferProvider.stateCode == 200) { + DashBoardProvider dashBoardProvider = Provider.of(context, listen: false); + dashBoardProvider.refreshDashboard(context: context, userType: UsersTypes.nurse); + } + } + + @override + void initState() { + WidgetsBinding.instance.addPostFrameCallback((_) async { + //need to get internal and external request type data.. + await Provider.of(context, listen: false).getData(); + }); + super.initState(); + } + + @override + void dispose() { + _deviceTransferProvider.reset(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + _deviceTransferProvider = Provider.of(context, listen: false); + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: context.translation.addAsset, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AssetPicker( + device: _pickedAsset, + showLoading: false, + labelColor: AppColor.white936, + iconColor: AppColor.neutral120, + label: 'Scan Asset'.addTranslation, + borderColor: AppColor.white936, + buttonColor: Colors.white, + showBorder: true, + onPick: (asset) async { + _pickedAsset = asset; + if (_pickedAsset?.site != null && _transferModel.transferType?.value == 1) { + await _deviceTransferProvider.getSiteData(siteId: int.tryParse(_pickedAsset!.site!.id.toString())); + _assetDestination.site = _deviceTransferProvider.internalAssetDestination?.site; + _assetDestination.building = null; + _assetDestination.floor = null; + _assetDestination.department = null; + } else if (_pickedAsset?.site != null && _transferModel.transferType?.value == 2) { + _assetDestination.site = null; + _assetDestination.building = null; + _assetDestination.floor = null; + _assetDestination.department = null; + } + + setState(() {}); + }), + 12.height, + AppTextFormField( + labelText: context.translation.assetNo, + backgroundColor: AppColor.fieldBgColor(context), + textAlign: TextAlign.center, + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + style: Theme.of(context).textTheme.titleMedium, + ), + 12.height, + AppTextFormField( + labelText: context.translation.serialNo, + backgroundColor: AppColor.fieldBgColor(context), + textAlign: TextAlign.center, + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + style: Theme.of(context).textTheme.titleMedium, + ), + 12.height, + //TODO need to indentify where to + 12.height, + //model.. + AutoCompleteGenericField( + clearAfterPick: false, + label: 'Asset Name'.addTranslation, + displayString: (item) => "", + onSearch: (query) async { + // final provider = Provider.of(context, listen: false); + // final list = await provider.getPartsList(partName: query); + // return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList(); + return []; + }, + initialValue: '', + // initialValue: model.partCatalogItem?.partNumber ?? "", + onPick: (part) { + setState(() {}); + }, + ), + 12.height, + //Asset Name.. + AutoCompleteGenericField( + clearAfterPick: false, + label: 'Manufacturer'.addTranslation, + displayString: (item) => "", + onSearch: (query) async { + // final provider = Provider.of(context, listen: false); + // final list = await provider.getPartsList(partName: query); + // return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList(); + return []; + }, + initialValue: '', + // initialValue: model.partCatalogItem?.partNumber ?? "", + onPick: (part) { + setState(() {}); + }, + ), + 12.height, + //manufacture.. + AutoCompleteGenericField( + clearAfterPick: false, + label: 'Model'.addTranslation, + displayString: (item) => "", + onSearch: (query) async { + // final provider = Provider.of(context, listen: false); + // final list = await provider.getPartsList(partName: query); + // return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList(); + return []; + }, + initialValue: '', + // initialValue: model.partCatalogItem?.partNumber ?? "", + onPick: (part) { + setState(() {}); + }, + ), + 12.height, + //model.. + AutoCompleteGenericField( + clearAfterPick: false, + label: 'Asset Name'.addTranslation, + displayString: (item) => "", + onSearch: (query) async { + // final provider = Provider.of(context, listen: false); + // final list = await provider.getPartsList(partName: query); + // return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList(); + return []; + }, + initialValue: '', + // initialValue: model.partCatalogItem?.partNumber ?? "", + onPick: (part) { + setState(() {}); + }, + ), + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.supplier, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: null, + showAsBottomSheet: true, + showShadow: false, + showCancel: true, + onSelect: (supplier) { + setState(() {}); + }, + ), + 12.height, + + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.site, + initialValue: _assetDestination.site, + disableValue: _pickedAsset?.site, + showShadow: false, + loading: _deviceTransferProvider.isSiteLoading, + enabled: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + onSelect: (value) { + _assetDestination.site = value; + _assetDestination.building = null; + _assetDestination.floor = null; + _assetDestination.department = null; + setState(() {}); + }, + ), + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.building, + initialValue: _assetDestination.building, + showShadow: false, + showAsBottomSheet: true, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.site?.buildings?.isNotEmpty ?? false, + staticData: _assetDestination.site?.buildings ?? [], + onSelect: (value) { + _assetDestination.building = value; + _assetDestination.floor = null; + _assetDestination.department = null; + setState(() {}); + }, + ), + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.floor, + showShadow: false, + showAsBottomSheet: true, + initialValue: _assetDestination.floor, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.building?.floors?.isNotEmpty ?? false, + staticData: _assetDestination.building?.floors ?? [], + onSelect: (value) { + _assetDestination.floor = value; + _assetDestination.department = null; + setState(() {}); + }, + ), + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.department, + showShadow: false, + showAsBottomSheet: true, + initialValue: _assetDestination.department, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.floor?.departments?.isNotEmpty ?? false, + staticData: _assetDestination.floor?.departments ?? [], + onSelect: (value) { + _assetDestination.department = value; + _assetDestination.room = null; + setState(() {}); + }, + ), + 12.height, + classificationWidget(label: 'Found'), + 12.height, + Text( + 'Asset Photo'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936), + ), + 12.height, + attachments.isEmpty + ? AttachmentPicker( + label: context.translation.attachImage, + attachment: attachments, + buttonColor: AppColor.black10, + onlyImages: true, + onChange: (value) { + setState(() {}); + }, + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), + ) + : MultiFilesPickerItem( + file: File(attachments.first.name ?? ''), + enabled: true, + onRemoveTap: (file) { + setState(() { + attachments.clear(); + }); + }, + ), + 12.height, + AppTextFormField( + backgroundColor: AppColor.fieldBgColor(context), + labelText: 'Remarks'.addTranslation, + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + showShadow: false, + onSaved: (text) { + _transferModel.comment = text; + }, + ), + // 100.height, + ], + ).toShadowContainer(context).paddingOnly(top: 20, start: 16, end: 16), + ).expanded, + 10.height, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.submitRequest, maxWidth: true, onPressed: _onSubmit), + ), + ], + ), + ), + ); + } + + Widget classificationWidget({String? label}) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Classification'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936), + ), + //TODO Need to set background and text color according to data.. + StatusLabel( + label: label, + radius: 4, + textColor: AppColor.getPriorityStatusTextColor(context, 81), + backgroundColor: AppColor.getPriorityStatusColor(context, 370), + ), + ], + ); + } + + Future validateRequest() async { + if (_pickedAsset == null) { + await Fluttertoast.showToast(msg: "Please Select Asset"); + return false; + } + if (_assetDestination.site == null) { + await Fluttertoast.showToast(msg: "Please Select Site"); + return false; + } + if (_assetDestination.building == null) { + await Fluttertoast.showToast(msg: "Please Select Building"); + return false; + } + if (_assetDestination.floor == null) { + await Fluttertoast.showToast(msg: "Please Select Floor"); + return false; + } + if (_assetDestination.department == null) { + await Fluttertoast.showToast(msg: "Please Select Department"); + return false; + } + return true; + } +} diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart new file mode 100644 index 00000000..f68f7fa1 --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart @@ -0,0 +1,116 @@ +import 'package:flutter/material.dart'; +import 'package:provider/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/modules/asset_inventory_module/models/session_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/pick_site_information_view.dart'; +import 'package:test_sa/modules/cm_module/service_request_detail_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_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import '../provider/asset_inventory_provider.dart'; + +class AssetInventoryPage extends StatefulWidget { + final int sessionId; + + const AssetInventoryPage({Key? key, required this.sessionId}) : super(key: key); + + @override + _AssetInventoryPageState createState() { + return _AssetInventoryPageState(); + } +} + +class _AssetInventoryPageState extends State { + late AssetInventoryProvider _assetInventoryProvider; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); + } + + Future getInitialData() async { + _assetInventoryProvider = Provider.of(context, listen: false); + ServiceRequestDetailProvider _provider = Provider.of(context, listen: false); + await _provider.getWorkOrderById(id: widget.sessionId); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + appBar: DefaultAppBar( + title: 'Inventory Session Request'.addTranslation, + onBackPress: () { + Navigator.pop(context); + }, + ), + body: DefaultTabController( + length: 2, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), + decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)), + child: TabBar( + padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), + labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, + unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, + unselectedLabelStyle: AppTextStyles.bodyText, + labelStyle: AppTextStyles.bodyText, + indicatorPadding: EdgeInsets.zero, + indicatorSize: TabBarIndicatorSize.tab, + dividerColor: Colors.transparent, + indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), + onTap: (index) { + }, + tabs: [ + Tab(text: 'Request Details'.addTranslation, height: 57.toScreenHeight), + Tab(text: '${'Scan Assets'.addTranslation} (1)', height: 57.toScreenHeight), + ], + ), + ), + 12.height, + TabBarView( + children: [ + AssetInventoryDetailView(sessionModel: SessionModel(),), + AssetInventoryScanAssetView(workOrderData: Provider.of(context,listen: false).currentWorkOrder!.data!,), + ], + ).expanded, + SafeArea( + top: false, + right: false, + left: false, + child: FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Scan Assets'.addTranslation, + onPressed: _scanAsset, + // buttonColor: AppColor.primary10, + ), + ), + ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), + ], + ), + )); + } + Future _scanAsset() async { + Navigator.push(context, MaterialPageRoute(builder: (contxt) => PickSiteInformationView(sessionModel: SessionModel()))); + } +} diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart new file mode 100644 index 00000000..419afd9c --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart @@ -0,0 +1,53 @@ + +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/string_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/new_models/work_order_detail_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_form_view.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 'asset_detail_card_view.dart'; + +class AssetInventoryScanAssetView extends StatelessWidget { + WorkOrderData workOrderData ; + AssetInventoryScanAssetView({Key? key,required this.workOrderData}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SafeArea( + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.separated( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) => AssetDetailCardView(workOrder:workOrderData), + separatorBuilder: (cxt, index) => 12.height, + itemCount: 4), + 12.height, + AppFilledButton( + label: "Add Asset".addTranslation, + maxWidth: true, + height: 70, + textColor: AppColor.textColor(context), + buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + showIcon: true, + onPressed:()=> _addAsset(context), + ), + ], + ).paddingOnly(start: 16, end: 16,), + ), + ); + } + void _addAsset(BuildContext context ){ + //TODO need to confirm navigation... + Navigator.push(context, MaterialPageRoute(builder: (contxt) => const AssetInventoryFormView())); + } +} diff --git a/lib/modules/asset_inventory_module/pages/inventory_seession_card.dart b/lib/modules/asset_inventory_module/pages/inventory_seession_card.dart new file mode 100644 index 00000000..9a0d6912 --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/inventory_seession_card.dart @@ -0,0 +1,133 @@ +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/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_page.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class InventorySessionCard extends StatelessWidget { + final Data? requestData; + final RequestsDetails? requestDetails; + final bool showShadow; + + const InventorySessionCard({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + if (requestData != null) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestData!.priorityName!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.priorityName!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.priorityName!), + ), + 8.width, + StatusLabel( + label: requestData!.statusName!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!), + ), + 1.width.expanded, + Text( + requestData!.transactionDate?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + (requestData?.typeTransaction ?? context.translation.taskRequest).heading5(context), + //TODO replace with Api Data.. + infoWidget(label: 'Type'.addTranslation, value: requestData?.requestNo, context: context), + infoWidget(label: 'Assets'.addTranslation, value: requestData?.assetName, context: context), + infoWidget(label: 'Sites'.addTranslation, value: requestData?.assetNumber, context: context), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => AssetInventoryPage( + sessionId: requestData!.id!, + ))); + }); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestDetails!.priority!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.priority!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.priority!), + ), + 8.width, + StatusLabel( + label: requestDetails!.status!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!), + ), + 1.width.expanded, + Text( + requestDetails!.date?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + (requestDetails?.nameOfType ?? context.translation.taskRequest).heading5(context), + 8.height, + //TODO replace with Api Data.. + infoWidget(label: 'Type'.addTranslation, value: requestDetails?.requestNo, context: context), + infoWidget(label: 'Assets'.addTranslation, value: requestDetails?.assetName, context: context), + infoWidget(label: 'Sites'.addTranslation, value: requestDetails?.site, context: context), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => AssetInventoryPage( + sessionId: requestDetails!.id!, + ))); + }); + } + + Widget infoWidget({required String label, String? value, required BuildContext context}) { + if (value != null && value.isNotEmpty) { + return '$label: $value'.bodyText(context); + } + return const SizedBox(); + } +} diff --git a/lib/modules/asset_inventory_module/pages/pick_site_information_view.dart b/lib/modules/asset_inventory_module/pages/pick_site_information_view.dart new file mode 100644 index 00000000..b784f08e --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/pick_site_information_view.dart @@ -0,0 +1,225 @@ +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:provider/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/models/device/asset.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/room_model.dart'; +import 'package:test_sa/models/new_models/work_order_detail_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/asset_detail_card_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_form_view.dart'; +import 'package:test_sa/modules/cm_module/service_request_detail_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_filled_button.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/providers/gas_request_providers/site_provider.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +import '../../../models/new_models/site.dart'; + +class PickSiteInformationView extends StatefulWidget { + SessionModel sessionModel; + + PickSiteInformationView({Key? key, required this.sessionModel}) : super(key: key); + + @override + State createState() => _PickSiteInformationViewState(); +} + +class _PickSiteInformationViewState extends State { + late SessionModel _sessionModel; + + //TODO need to remove this ... + Asset _assetDestination = Asset(); + late ServiceRequestDetailProvider _requestDetailProvider; + + void _onSave() async {} + + @override + void initState() { + _sessionModel = widget.sessionModel; + super.initState(); + } + + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + _requestDetailProvider = Provider.of(context, listen: false); + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: 'Inventory Session Request'.addTranslation, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Column( + children: [ + SingleChildScrollView( + child: Column( + children: [ + siteInfoCard(context), + 12.height, + assetDetailCard(context, _requestDetailProvider.currentWorkOrder!.data!), + 12.height, + AppFilledButton( + label: "Add Asset".addTranslation, + maxWidth: true, + height: 70, + textColor: AppColor.textColor(context), + buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + showIcon: true, + onPressed: _addAsset, + ), + 12.height, + ], + ).paddingOnly(start: 16, end: 16, top: 16), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.save, maxWidth: true, onPressed: _onSave), + ), + ], + ) + ); + } + void _addAsset(){ + Navigator.push(context, MaterialPageRoute(builder: (contxt) => const AssetInventoryFormView())); + } + Widget assetDetailCard(BuildContext context, WorkOrderData workOrder) { + + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.separated( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) => AssetDetailCardView(workOrder:workOrder), + separatorBuilder: (cxt, index) => 12.height, + itemCount: 4), + ], + ); + } + + + Widget siteInfoCard(BuildContext context,){ + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.site, + initialValue: _assetDestination.site, + showShadow: false, + // loading: _deviceTransferProvider.isSiteLoading, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + onSelect: (value) { + _assetDestination.site = value; + _assetDestination.building = null; + _assetDestination.floor = null; + _assetDestination.department = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.building, + initialValue: _assetDestination.building, + showShadow: false, + showAsBottomSheet: true, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.site?.buildings?.isNotEmpty ?? false, + staticData: _assetDestination.site?.buildings ?? [], + onSelect: (value) { + _assetDestination.building = value; + _assetDestination.floor = null; + _assetDestination.department = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.floor, + showShadow: false, + showAsBottomSheet: true, + initialValue: _assetDestination.floor, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.building?.floors?.isNotEmpty ?? false, + staticData: _assetDestination.building?.floors ?? [], + onSelect: (value) { + _assetDestination.floor = value; + _assetDestination.department = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.department, + showShadow: false, + showAsBottomSheet: true, + initialValue: _assetDestination.department, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.floor?.departments?.isNotEmpty ?? false, + staticData: _assetDestination.floor?.departments ?? [], + onSelect: (value) { + _assetDestination.department = value; + _assetDestination.room = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.room, + showShadow: false, + showAsBottomSheet: true, + initialValue: _assetDestination.room, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.department?.rooms?.isNotEmpty ?? false, + staticData: _assetDestination.department?.rooms ?? [], + onSelect: (value) { + _assetDestination.room = value; + setState(() {}); + }, + ), + 8.height, + ], + ).toShadowContainer(context); + } + + Future validateRequest() async { + if (_assetDestination.site == null) { + await Fluttertoast.showToast(msg: "Please Select Site"); + return false; + } + if (_assetDestination.building == null) { + await Fluttertoast.showToast(msg: "Please Select Building"); + return false; + } + if (_assetDestination.floor == null) { + await Fluttertoast.showToast(msg: "Please Select Floor"); + return false; + } + if (_assetDestination.department == null) { + await Fluttertoast.showToast(msg: "Please Select Department"); + return false; + } + return true; + } +} diff --git a/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart b/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart new file mode 100644 index 00000000..2d5de6c4 --- /dev/null +++ b/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart @@ -0,0 +1,62 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/models/service_request/pending_service_request_model.dart'; +import 'package:test_sa/models/service_request/service_report.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/models/service_request/service_request_search.dart'; +import 'package:test_sa/models/service_request/spare_parts.dart'; +import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart'; +import 'package:test_sa/models/service_request/supplier_engineer_model.dart'; +import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; + +import '../../../models/service_request/search_work_order.dart'; +import '../../../models/service_request/wo_call_request.dart'; +import '../../../models/user.dart'; +import '../../../new_views/common_widgets/app_lazy_loading.dart'; + +class AssetInventoryProvider extends ChangeNotifier { + final pageItemNumber = 10; + + SessionModel? sessionModel; + + void reset() { + nextPage = true; + stateCode = null; + } + + int? stateCode; + bool isDetailLoading = false; + bool nextPage = true; + bool isLoading = false; + + Future getSessionById({required int id}) async { + try { + isLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get(URLs.getAssetInventoryById + "?assetInventoryId=$id"); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + sessionModel = await SessionModel.fromJson(json.decode(response.body)); + } else { + sessionModel = null; + } + isLoading = false; + notifyListeners(); + } catch (e) { + log("getSessionError [error] : $e"); + isLoading = false; + sessionModel = null; + notifyListeners(); + return null; + } + } +} diff --git a/lib/new_views/pages/land_page/contact_us_bottom_sheet.dart b/lib/new_views/pages/land_page/contact_us_bottom_sheet.dart index 3d35de8e..784a125e 100644 --- a/lib/new_views/pages/land_page/contact_us_bottom_sheet.dart +++ b/lib/new_views/pages/land_page/contact_us_bottom_sheet.dart @@ -1,11 +1,9 @@ -import 'package:clipboard/clipboard.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/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/models/site_contact_info_model.dart'; @@ -77,7 +75,7 @@ class ContactUsBottomSheet extends StatelessWidget { padding: EdgeInsets.zero, iconSize: 20, onPressed: () { - FlutterClipboard.copy('Hello Flutter friends'); + // FlutterClipboard.copy('Hello Flutter friends'); }, ) ], diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index 23f1c89a..d7fb13c4 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -3,10 +3,12 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_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/models/enums/user_types.dart'; @@ -50,7 +52,7 @@ class _MyRequestsPageState extends State { if (context.settingProvider.isUserFlowMedical) { requestsList.add(Request(7, 'Recall and Alert')); } - + requestsList.add(Request(8, 'Inventory Session'.addTranslation)); _provider = Provider.of(context, listen: false); _provider!.reset(); WidgetsBinding.instance.addPostFrameCallback((_) { diff --git a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart index ace4047f..d27e9a4d 100644 --- a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart +++ b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/inventory_seession_card.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; @@ -45,44 +46,29 @@ class RequestPaginatedListview extends StatelessWidget { } Widget _buildRequestItem(Data request) { - bool isServiceRequest = request.transactionNo == 1; - bool isGasRefill = request.transactionNo == 2; - bool isAssetTransfer = request.transactionNo == 3; - bool isPPMs = request.transactionNo == 4; - bool isRecurrentTask = request.transactionNo == 5; - bool isTask = request.transactionNo == 6; - - if (isServiceRequest) { - return ServiceRequestItemView(requestData: request, refreshData: false); - } else if (isGasRefill) { - return GasRefillItemView(requestData: request); - } else if (isPPMs) { - return PpmItemView(requestData: request); - } else if (isAssetTransfer) { - return DeviceItemView(requestData: request); - } else if (isRecurrentTask) { - return RecurrentWoItemView(requestData: request); - } else if (isTask) { - return TaskRequestItemView(requestData: request); - } else { - return Container( - height: 100, - width: double.infinity, - color: Colors.grey, - ); + switch (request.transactionNo) { + case 1: + return ServiceRequestItemView(requestData: request); + case 2: + return GasRefillItemView(requestData: request); + case 3: + return DeviceItemView(requestData: request); + case 4: + return PpmItemView(requestData: request); + case 5: + return RecurrentWoItemView(requestData: request); + case 6: + return TaskRequestItemView(requestData: request); + case 7: + return TaskRequestItemView(requestData: request); + case 8: + return InventorySessionCard(requestData: request); + default: + return Container( + height: 100, + width: double.infinity, + color: Colors.grey, + ); } } } - -// return Column( -// mainAxisSize: MainAxisSize.min, -// children: List.generate(isLoading ? 6 : list.length, (index) { -// // if (isLoading) { -// // return const SizedBox().toRequestShimmer(context, isLoading); -// // } -// // else { -// return Padding( -// padding: EdgeInsets.symmetric(vertical: 10.toScreenHeight), -// child: _buildRequestItem(list[index])); -// // } -// })); diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index a3548947..6a2c20f2 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -4,6 +4,7 @@ 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/models/all_requests_and_count_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/inventory_seession_card.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart'; @@ -29,7 +30,8 @@ class RequestItemViewList extends StatelessWidget { if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); switch (list[index].transactionType) { case 1: - return ServiceRequestItemView(requestDetails: list[index]); + // return ServiceRequestItemView(requestDetails: list[index]); + return InventorySessionCard(requestDetails: list[index]); case 2: return GasRefillItemView(requestDetails: list[index]); case 3: @@ -42,6 +44,8 @@ class RequestItemViewList extends StatelessWidget { return TaskRequestItemView(requestDetails: list[index]); case 7: return TaskRequestItemView(requestDetails: list[index]); + case 8: + return InventorySessionCard(requestDetails: list[index]); default: Container( height: 100, diff --git a/lib/views/widgets/equipment/asset_picker.dart b/lib/views/widgets/equipment/asset_picker.dart index a9d8e5f0..78a687ab 100644 --- a/lib/views/widgets/equipment/asset_picker.dart +++ b/lib/views/widgets/equipment/asset_picker.dart @@ -17,8 +17,12 @@ class AssetPicker extends StatelessWidget { final List deviceList; final bool editable; final bool showAssetInfo; + final bool showBorder; final Color? borderColor; final Color? buttonColor; + final Color? iconColor; + final Color? labelColor; + final String? label; Color? backgroundColor; final bool forPPM; final bool showLoading; @@ -34,8 +38,12 @@ class AssetPicker extends StatelessWidget { this.onAssetRemove, this.borderColor, this.buttonColor, + this.label, + this.iconColor, + this.labelColor, this.backgroundColor, this.showAssetInfo = true, + this.showBorder = false, this.multiSelection = false, this.forPPM = false, this.showLoading = false}) @@ -57,15 +65,16 @@ class AssetPicker extends StatelessWidget { decoration: BoxDecoration( color: buttonColor ?? backgroundColor ?? AppColor.blueStatus(context), borderRadius: BorderRadius.circular(10), + border: showBorder?Border.all(color: borderColor ?? AppColor.blueStatus(context), width: 2):null, // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)], ), padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), child: Row( mainAxisSize: MainAxisSize.min, children: [ - "scan_asset".toSvgAsset(height: 22, fit: BoxFit.fitHeight, color: context.isDark ? AppColor.neutral20 : Colors.white), + "scan_asset".toSvgAsset(height: 22, fit: BoxFit.fitHeight, color: context.isDark ? AppColor.neutral20 :iconColor?? Colors.white), 8.width, - "Scan or Pick Asset".bodyText(context).custom(color: context.isDark ? AppColor.neutral20 : Colors.white), + ' ${label??"Scan or Pick Asset"}'.bodyText(context).custom(color: context.isDark ? AppColor.neutral20 : labelColor?? Colors.white), ], ), ).onPress(() async { diff --git a/pubspec.lock b/pubspec.lock index 484acd6c..1b05ec91 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -177,6 +177,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.1" + clipboard: + dependency: "direct main" + description: + name: clipboard + sha256: "1920c0337f8808be4166c5f1b236301ff381ef69633b0757c502d97f1f740102" + url: "https://pub.dev" + source: hosted + version: "2.0.2" clock: dependency: transitive description: