asset inventory module ready for qa

design_3.0_asset_inventory_module
WaseemAbbasi22 3 weeks ago
parent c19fdb173b
commit 8578319cc3

@ -1,144 +0,0 @@
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<T extends Object> extends StatefulWidget {
final String? label;
final String initialValue;
final bool clearAfterPick;
final Future<List<T>> 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<AutoCompleteGenericField<T>> createState() => _AutoCompleteGenericFieldState<T>();
}
class _AutoCompleteGenericFieldState<T extends Object> extends State<AutoCompleteGenericField<T>> {
late TextEditingController _controller;
List<T> _options = [];
bool _isLoading = false;
@override
void initState() {
_controller = TextEditingController(text: widget.initialValue);
super.initState();
}
@override
void didUpdateWidget(covariant AutoCompleteGenericField<T> oldWidget) {
if (widget.initialValue != oldWidget.initialValue) {
_controller.text = widget.initialValue;
}
super.didUpdateWidget(oldWidget);
}
Future<void> _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<T>(
// 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),
);
},
),
),
),
);
},
),
);
}
}

@ -0,0 +1,124 @@
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/models/lookup.dart';
import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../../extensions/text_extensions.dart';
import '../../../new_views/app_style/app_text_style.dart';
class LookUpAutoCompleteField extends StatefulWidget {
final String initialValue;
final String label;
final num? assetId;
final bool forAssetName;
final bool forSupplier;
final bool clearAfterPick, isManufacturer;
final Function(Lookup) onPick;
final Function(String) onChanged;
//need to pass directly url
const LookUpAutoCompleteField(
{Key? key,
this.isManufacturer = false,
required this.initialValue,
required this.label,
this.forAssetName = false,
this.forSupplier = false,
this.assetId,
required this.onPick,
this.clearAfterPick = true,
required this.onChanged})
: super(key: key);
@override
_AutoCompletePartsFieldState createState() => _AutoCompletePartsFieldState();
}
class _AutoCompletePartsFieldState extends State<LookUpAutoCompleteField> {
AssetInventoryProvider? assetInventoryProvider;
late TextEditingController _controller;
@override
void initState() {
_controller = TextEditingController(text: widget.initialValue);
super.initState();
}
@override
void didUpdateWidget(covariant LookUpAutoCompleteField oldWidget) {
if (widget.initialValue != oldWidget.initialValue) {
_controller = TextEditingController(text: widget.initialValue);
}
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
assetInventoryProvider ??= Provider.of<AssetInventoryProvider>(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)),
// boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
child: Autocomplete<Lookup>(
optionsBuilder: (TextEditingValue textEditingValue) async {
if (textEditingValue.text.isEmpty) {
return const Iterable<Lookup>.empty();
}
return (await assetInventoryProvider!.getAutoCompleteDetails(query: textEditingValue.text, isManufacturer: widget.isManufacturer, type: widget.forAssetName?1:widget.forSupplier?2:0));
},
displayStringForOption: (Lookup option) => option.name ?? "",
fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback 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),
constraints: const BoxConstraints(),
suffixIconConstraints: const BoxConstraints(minWidth: 0),
filled: true,
fillColor: AppColor.fieldBgColor(context),
errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60),
floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20),
labelText: widget.label,
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
),
textInputAction: TextInputAction.search,
onChanged: (text) {
widget.onChanged(text);
fieldTextEditingController.text = text;
},
onSubmitted: (String value) {
onFieldSubmitted();
},
);
},
onSelected: (Lookup selection) {
if (widget.clearAfterPick) {
_controller.clear();
} else {
_controller.text = selection.name ?? '';
}
widget.onPick(selection);
},
),
);
}
}

@ -298,7 +298,24 @@ class URLs {
// asset inventory Urls.
static get getAssetInventoryById => '$_baseUrl/AssetInventory/GetAssetInventoryById';
static get getAssetsInSession => '$_baseUrl/AssetInventory/GetAssetsInSeassion';
static get getInventoryDetailsByFilter => '$_baseUrl/AssetInventory/GetInventoryDetailsByFilter';
static get searchAsset => '$_baseUrl/AssetInventory/SearchAsset';
static get saveAssetInSession => '$_baseUrl/AssetInventory/SaveAssetInSession';
static get deleteAssetInSession => '$_baseUrl/AssetInventory/DeleteAssetInSession';
static get getManufacturerOrModelAutoComplete => '$_baseUrl/AssetInventory/GetManufacturerOrModelAutoComplete';
static get searchAssetName => '$_baseUrl/AssetInventory/SearchAssetName';
static get getSuppliersAutoCompleteInventory => '$_baseUrl/Supplier/GetSuppliersMobile';
static get getAssetsTemp => '$_baseUrl/AssetInventory/GetAssetsTemp';
static get convertDetailToComplete => '$_baseUrl/AssetInventory/ConvertDetailToComplete';
}

@ -48,7 +48,6 @@ class GasRefillCommentsProvider extends ChangeNotifier {
late Response response;
try {
response = await ApiManager.instance.get(URLs.getGazRefillComments + "?gasRefillId=$callId");
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
List requestsListJson = json.decode(response.body)["data"];

@ -123,11 +123,14 @@ class RequestsDetails {
String? statusReceiver;
String? assetTransferFrom;
String? assetTransferTo;
String? sessionType;
String? code;
String? date;
String? siteTransferFrom;
String? siteTransferTo;
int? transactionType;
int? numberOfAssets;
int? numberOfSites;
RequestsDetails(
{this.id,
@ -142,6 +145,9 @@ class RequestsDetails {
this.manufacturer,
this.requestType,
this.requestNo,
this.numberOfAssets,
this.numberOfSites,
this.sessionType,
this.gasType,
this.site,
this.statusReceiver,
@ -165,6 +171,9 @@ class RequestsDetails {
supplier = json['supplier'];
manufacturer = json['manufacturer'];
requestType = json['requestType'];
sessionType = json['sessionType'];
numberOfAssets = json['numberOfAssets'];
numberOfSites = json['numberOfSites'];
requestNo = json['requestNo'];
gasType = json['gasType'];
site = json['site'];
@ -197,6 +206,9 @@ class RequestsDetails {
data['statusReceiver'] = statusReceiver;
data['assetTransferFrom'] = assetTransferFrom;
data['assetTransferTo'] = assetTransferTo;
data['sessionType'] = sessionType;
data['numberOfSites'] = numberOfSites;
data['numberOfAssets'] = numberOfAssets;
data['code'] = code;
data['date'] = date;
data['siteTransferFrom'] = siteTransferFrom;

@ -142,11 +142,11 @@ class Asset {
Building? building; // Now nullable
Floor? floor; // Now nullable
Department? department; // Now nullable
Rooms? room;
MappedSite? mappedSite; // Now nullable
MappedBuilding? mappedBuilding; // Now nullable
MappedFloor? mappedFloor; // Now nullable
MappedDepartment? mappedDepartment; // No
Rooms? room; // Now nullable
MappedDepartment? mappedDepartment; //
num? testsDay; // Now nullable
num? purchasingPrice; // Now nullable
String? nbv; // Now nullable

@ -50,17 +50,34 @@ class Data {
String? priorityName;
bool? isHighPriority;
String? assetName;
String? sessionType;
String? rejectReason;
String? assetNumber;
String? requestTypeName;
String? requestNo;
int? transactionNo;
int? numberOfSites;
int? numberOfAssets;
String? nameOfType;
Data({this.id, this.typeTransaction, this.nameOfType,this.transactionDate, this.statusName, this.priorityName, this.isHighPriority, this.assetName, this.assetNumber, this.requestTypeName, this.requestNo,this.transactionNo});
Data(
{this.id,
this.typeTransaction,
this.nameOfType,
this.transactionDate,
this.statusName,
this.numberOfAssets,
this.numberOfSites,
this.sessionType,
this.priorityName,
this.isHighPriority,
this.assetName,
this.assetNumber,
this.requestTypeName,
this.requestNo,
this.transactionNo});
Data.fromJson(Map<String, dynamic> json) {
id = json['id'];
typeTransaction = json['typeTransaction'];
transactionDate = json['transactionDate'];
@ -68,6 +85,9 @@ class Data {
priorityName = json['priorityName'];
isHighPriority = json['isHighPriority'];
assetName = json['assetName'];
sessionType = json['sessionType'];
numberOfSites = json['numberOfSites'];
numberOfAssets = json['numberOfAssets'];
assetNumber = json['assetNumber'];
requestTypeName = json['requestTypeName'];
requestNo = json['requestNo'];
@ -90,6 +110,9 @@ class Data {
data['requestNo'] = requestNo;
data['rejectReason'] = rejectReason;
data['transactionNo'] = transactionNo;
data['sessionType'] = sessionType;
data['numberOfAssets'] = numberOfAssets;
data['numberOfSites'] = numberOfSites;
data['nameOfType'] = nameOfType;
return data;
}

@ -1,3 +1,12 @@
import 'dart:developer';
import 'package:test_sa/models/new_models/building.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/site.dart';
import 'package:test_sa/models/service_request/supplier_details.dart';
import '../../../models/new_models/department.dart';
class AssetInventoryResponse {
num? totalRows;
num? count;
@ -28,9 +37,7 @@ class AssetInventoryResponse {
responseCode = json['responseCode'];
isSuccess = json['isSuccess'];
if (json['data'] != null) {
assetList = (json['data'] as List)
.map((item) => AssetInventoryModel.fromJson(item))
.toList();
assetList = (json['data'] as List).map((item) => AssetInventoryModel.fromJson(item)).toList();
}
}
@ -43,7 +50,6 @@ class AssetInventoryResponse {
'innerMessage': innerMessage,
'responseCode': responseCode,
'isSuccess': isSuccess,
// assetList not needed in toJson because youll likely only send AssetInventoryModel for updates
};
}
}
@ -54,68 +60,69 @@ class AssetInventoryModel {
String? assetNumber;
String? serialNo;
String? assetName;
num? assetNameId;
String? model;
String? manufacturer;
String? supplierName;
String? site;
String? building;
String? floor;
String? department;
String? room;
String? siteName;
String? buildingName;
String? floorName;
String? departmentName;
String? roomName;
num? statusId;
String? status;
num? statusValue;
num? statusByAdminId;
String? statusByAdmin;
num? statusByAdminValue;
bool? isNotRegistered;
num? sessionId;
num? assetImportId;
num? siteId;
num? supplierId;
num? buildingId;
num? floorId;
num? departmentId;
num? roomId;
String? oldAssetNumber;
String? newAssetNumber;
String? oldSerialNo;
String? newSerialNo;
num? oldAssetNameId;
num? newAssetNameId;
String? newAssetNameText;
num? oldModelId;
num? newModelId;
String? newModelName;
num? oldManufacturerId;
num? manufacturerId;
num? modelId;
num? newManufacturerId;
String? newManufacturerName;
num? oldSupplierId;
num? newSupplierId;
String? newSupplierName;
String? photo;
String? photoOriginName;
String? remarks;
num? oldSiteId;
num? oldBuildingId;
num? oldFloorId;
num? oldDepartmentId;
num? oldRoomId;
Site? site;
Building? building;
Floor? floor;
Department? department;
Rooms? room;
SupplierDetails? supplier;
AssetInventoryModel({
this.id,
this.sessionId,
this.assetId,
this.assetNumber,
this.assetNameId,
this.serialNo,
this.assetName,
this.model,
this.manufacturer,
this.supplierName,
this.site,
this.building,
this.floor,
this.department,
this.room,
this.siteName,
this.buildingName,
this.floorName,
this.departmentName,
this.roomName,
this.statusId,
this.status,
this.statusValue,
@ -123,92 +130,79 @@ class AssetInventoryModel {
this.statusByAdmin,
this.statusByAdminValue,
this.isNotRegistered,
this.sessionId,
this.assetImportId,
this.siteId,
this.buildingId,
this.floorId,
this.departmentId,
this.supplierId,
this.roomId,
this.oldAssetNumber,
this.newAssetNumber,
this.oldSerialNo,
this.manufacturerId,
this.newSerialNo,
this.oldAssetNameId,
this.newAssetNameId,
this.newAssetNameText,
this.oldModelId,
this.newModelId,
this.modelId,
this.newModelName,
this.oldManufacturerId,
this.newManufacturerId,
this.newManufacturerName,
this.oldSupplierId,
this.newSupplierId,
this.newSupplierName,
this.photo,
this.photoOriginName,
this.remarks,
this.oldSiteId,
this.oldBuildingId,
this.oldFloorId,
this.oldDepartmentId,
this.oldRoomId,
this.site,
this.department,
this.building,
this.floor,
this.room,
this.supplier,
});
AssetInventoryModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
assetId = json['assetId'];
assetNumber = json['assetNumber'];
assetNameId = json['assetNameId'];
serialNo = json['serialNo'];
assetName = json['assetName'];
model = json['model'];
manufacturer = json['manufacturer'];
model = json['model'] ?? json['modelName'];
manufacturer = json['manufacturer'] ?? json['manufacturerName'];
supplierName = json['supplierName'];
site = json['site'];
building = json['building'];
floor = json['floor'];
department = json['department'];
room = json['room'];
siteName = json['site'] ?? json['siteName'];
buildingName = json['building'] ?? json['buildingName'];
floorName = json['floor'] ?? json['floorName'];
departmentName = json['department'] ?? json['departmentName'];
roomName = json['room'] ?? json['roomName'];
statusId = json['statusId'];
status = json['status'];
status = json['status'] ?? json['classification'];
statusValue = json['statusValue'];
statusByAdminId = json['statusByAdminId'];
statusByAdmin = json['statusByAdmin'];
statusByAdminValue = json['statusByAdminValue'];
isNotRegistered = json['isNotRegistered'];
sessionId = json['sessionId'];
assetImportId = json['assetImportId'];
assetImportId = json['assetImportId']??json['id'];
siteId = json['siteId'];
buildingId = json['buildingId'];
floorId = json['floorId'];
supplierId = json['supplierId'];
departmentId = json['departmentId'];
roomId = json['roomId'];
oldAssetNumber = json['oldAssetNumber'];
newAssetNumber = json['newAssetNumber'];
oldSerialNo = json['oldSerialNo'];
newSerialNo = json['newSerialNo'];
oldAssetNameId = json['oldAssetNameId'];
newAssetNameId = json['newAssetNameId'];
newAssetNameText = json['newAssetNameText'];
oldModelId = json['oldModelId'];
newModelId = json['newModelId'];
newModelName = json['newModelName'];
oldManufacturerId = json['oldManufacturerId'];
newManufacturerId = json['newManufacturerId'];
newManufacturerName = json['newManufacturerName'];
oldSupplierId = json['oldSupplierId'];
newSupplierId = json['newSupplierId'];
newSupplierName = json['newSupplierName'];
modelId = json['modelId'];
photo = json['photo'];
photoOriginName = json['photoOriginName'];
remarks = json['remarks'];
oldSiteId = json['oldSiteId'];
oldBuildingId = json['oldBuildingId'];
oldFloorId = json['oldFloorId'];
oldDepartmentId = json['oldDepartmentId'];
oldRoomId = json['oldRoomId'];
//new data..
// newAssetNumber = json['newAssetNumber'] ?? json['assetNumber'];
// manufacturerId = json['manufacturerId'] ?? json['manufacturerId'];
// newSerialNo = json['newSerialNo'] ?? json['serialNo'];
// newAssetNameId = json['newAssetNameId'] ?? json['assetNameId'];
// newAssetNameText = json['newAssetNameText'] ?? json['assetNameText'];
// newModelId = json['newModelId'] ?? json['modelId'];
// newModelName = json['newModelName'] ?? json['modelName'];
// newManufacturerId = json['newManufacturerId'] ?? json['manufacturerId'];
// newManufacturerName = json['newManufacturerName'] ?? json['manufacturerName'];
// newSupplierId = json['newSupplierId'] ?? json['supplierId'];
// newSupplierName = json['newSupplierName'] ?? json['supplierName'];
}
Map<String, dynamic> toJson() {
@ -222,30 +216,76 @@ class AssetInventoryModel {
'floorId': floorId,
'departmentId': departmentId,
'roomId': roomId,
'oldAssetNumber': oldAssetNumber,
'newAssetNumber': newAssetNumber,
'oldSerialNo': oldSerialNo,
'newSerialNo': newSerialNo,
'oldAssetNameId': oldAssetNameId,
'newAssetNameId': newAssetNameId,
'newAssetNameText': newAssetNameText,
'oldModelId': oldModelId,
'newModelId': newModelId,
'newModelName': newModelName,
'oldManufacturerId': oldManufacturerId,
'newManufacturerId': newManufacturerId,
'newManufacturerName': newManufacturerName,
'oldSupplierId': oldSupplierId,
'newSupplierId': newSupplierId,
'newSupplierName': newSupplierName,
'photo': photo,
'photoOriginName': photoOriginName,
'remarks': remarks,
'oldSiteId': oldSiteId,
'oldBuildingId': oldBuildingId,
'oldFloorId': oldFloorId,
'oldDepartmentId': oldDepartmentId,
'oldRoomId': oldRoomId,
};
}
AssetInventoryModel mergeWith(AssetInventoryModel? other) {
if (other == null) return this;
return AssetInventoryModel(
id: id ?? other.id,
assetId: assetId ?? other.assetId,
assetNumber: assetNumber ?? other.assetNumber,
serialNo: serialNo ?? other.serialNo,
assetName: assetName ?? other.assetName,
assetNameId: assetNameId ?? other.assetNameId,
model: model ?? other.model,
manufacturer: manufacturer ?? other.manufacturer,
supplierName: supplierName ?? other.supplierName,
siteName: siteName ?? other.siteName,
buildingName: buildingName ?? other.buildingName,
floorName: floorName ?? other.floorName,
departmentName: departmentName ?? other.departmentName,
roomName: roomName ?? other.roomName,
statusId: statusId ?? other.statusId,
status: status ?? other.status,
statusValue: statusValue ?? other.statusValue,
statusByAdminId: statusByAdminId ?? other.statusByAdminId,
statusByAdmin: statusByAdmin ?? other.statusByAdmin,
statusByAdminValue: statusByAdminValue ?? other.statusByAdminValue,
isNotRegistered: isNotRegistered ?? other.isNotRegistered,
sessionId: sessionId ?? other.sessionId,
assetImportId: assetImportId ?? other.assetImportId,
siteId: siteId ?? other.siteId,
supplierId: supplierId ?? other.supplierId,
buildingId: buildingId ?? other.buildingId,
floorId: floorId ?? other.floorId,
departmentId: departmentId ?? other.departmentId,
roomId: roomId ?? other.roomId,
newAssetNumber: newAssetNumber ?? other.newAssetNumber,
newSerialNo: newSerialNo ?? other.newSerialNo,
newAssetNameId: newAssetNameId ?? other.newAssetNameId,
newAssetNameText: newAssetNameText ?? other.newAssetNameText,
newModelId: newModelId ?? other.newModelId,
newModelName: newModelName ?? other.newModelName,
manufacturerId: manufacturerId ?? other.manufacturerId,
modelId: modelId ?? other.modelId,
newManufacturerId: newManufacturerId ?? other.newManufacturerId,
newManufacturerName: newManufacturerName ?? other.newManufacturerName,
newSupplierId: newSupplierId ?? other.newSupplierId,
newSupplierName: newSupplierName ?? other.newSupplierName,
photo: photo ?? other.photo,
photoOriginName: photoOriginName ?? other.photoOriginName,
remarks: remarks ?? other.remarks,
site: site ?? other.site,
building: building ?? other.building,
floor: floor ?? other.floor,
department: department ?? other.department,
room: room ?? other.room,
supplier: supplier ?? other.supplier,
);
}
}

@ -5,6 +5,7 @@ class SessionModel {
int? id;
String? sessionName;
int? sessionTypeId;
int? sessionTypeValue;
String? sessionTypeName;
int? statusId;
String? statusName;
@ -17,6 +18,7 @@ class SessionModel {
this.id,
this.sessionName,
this.sessionTypeId,
this.sessionTypeValue,
this.sessionTypeName,
this.statusId,
this.statusName,
@ -33,6 +35,7 @@ class SessionModel {
id = json['id'];
sessionName = json['sessionName'];
sessionTypeId = json['sessionTypeId'];
sessionTypeValue = json['sessionTypeValue'];
sessionTypeName = json['sessionTypeName'];
statusId = json['statusId'];
statusName = json['statusName'];
@ -53,6 +56,7 @@ class SessionModel {
map['id'] = id;
map['sessionName'] = sessionName;
map['sessionTypeId'] = sessionTypeId;
map['sessionTypeValue'] = sessionTypeValue;
map['sessionTypeName'] = sessionTypeName;
map['statusId'] = statusId;
map['statusName'] = statusName;

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart';
@ -11,10 +13,12 @@ import 'package:test_sa/views/widgets/loaders/image_loader.dart';
class AssetDetailCardView extends StatelessWidget {
AssetInventoryModel assetInventoryModel;
VoidCallback onDeletePress;
AssetDetailCardView({
super.key,
required this.assetInventoryModel,
required this.onDeletePress,
});
@override
@ -30,6 +34,10 @@ class AssetDetailCardView extends StatelessWidget {
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
// 8.height,
Text(
'${context.translation.assetNumber}: ${assetInventoryModel.assetNumber ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.serialNo}: ${assetInventoryModel.serialNo ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
@ -43,11 +51,19 @@ class AssetDetailCardView extends StatelessWidget {
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.site}: ${assetInventoryModel.site ?? ''}',
'${context.translation.site}: ${assetInventoryModel.siteName ?? ''}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.building}: ${assetInventoryModel.buildingName ?? ''}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.floor}: ${assetInventoryModel.floorName ?? ''}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.department}: ${assetInventoryModel.department ?? ''}',
'${context.translation.department}: ${assetInventoryModel.departmentName ?? ''}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
@ -64,19 +80,9 @@ class AssetDetailCardView extends StatelessWidget {
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..
})
],
),
onDeletePress();
}),
20.height,
Container(
decoration: BoxDecoration(color: AppColor.neutral100, borderRadius: BorderRadius.circular(15)),

@ -1,81 +1,82 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:test_sa/common_widgets/autocomplete_generic_field.dart';
import 'package:flutter_advanced_switch/flutter_advanced_switch.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart';
import 'package:test_sa/controllers/providers/api/all_requests_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/generic_attachment_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/asset_inventory_module/models/asset_inventory_model.dart';
import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_page.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart';
import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.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_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/providers/work_order/vendor_provider.dart';
import 'package:test_sa/views/widgets/equipment/asset_picker.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/requests/request_status.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 'asset_inventory_site_information_view.dart';
class AssetInventoryFormView extends StatefulWidget {
static const String id = "/asset-inventory-form";
// TODO need to use only one model AssetInventoryModel everywhere after completing flow .
Asset ? assetLocation;
AssetInventoryModel? assetInventoryModel;
int? sessionTypeValue;
AssetInventoryFormView({Key? key,this.assetLocation}) : super(key: key);
AssetInventoryFormView({Key? key, this.assetInventoryModel, this.sessionTypeValue}) : super(key: key);
@override
State<AssetInventoryFormView> createState() => _AssetInventoryFormViewState();
}
class _AssetInventoryFormViewState extends State<AssetInventoryFormView> {
final AssetInventoryModel _assetInventoryModel = AssetInventoryModel();
AssetInventoryModel? _scannedAssetModel = AssetInventoryModel();
AssetInventoryModel? _pickedAssetModel = AssetInventoryModel();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
Asset? _pickedAsset;
final TextEditingController _assetNoController = TextEditingController();
final TextEditingController _serialNoController = TextEditingController();
final TextEditingController _remarksController = TextEditingController();
ValueNotifier<bool>? registeredController;
bool isRegistered = false;
final List<GenericAttachmentModel> attachments = [];
// TextEditingController _assetModelController = TextEditingController();
// TextEditingController _assetManufacturerController = TextEditingController();
// TextEditingController _assetSupplierController = TextEditingController();
void _onSubmit() async {
_assetInventoryModel.assetId = _pickedAsset?.id;
_assetInventoryModel.oldSiteId = widget.assetLocation?.site?.id;
_assetInventoryModel.oldBuildingId = widget.assetLocation?.building?.id;
_assetInventoryModel.oldFloorId = widget.assetLocation?.floor?.id;
_assetInventoryModel.oldDepartmentId = widget.assetLocation?.department?.id;
_assetInventoryModel.oldRoomId = widget.assetLocation?.room?.id;
final List<GenericAttachmentModel> attachments = [];
if (!_formKey.currentState!.validate() || !(await validateRequest())) {
return;
}
_formKey.currentState!.save();
//TODO need to confirm attachment structure and final api calling .
// List<AssetTransferAttachment> 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));
// }
// _assetInventoryModel.attachments = attachement;
// await _deviceTransferProvider.createRequest(
// context: context,
// model: _transferModel,
// );
// if (_deviceTransferProvider.stateCode == 200) {
// DashBoardProvider dashBoardProvider = Provider.of<DashBoardProvider>(context, listen: false);
// dashBoardProvider.refreshDashboard(context: context, userType: UsersTypes.nurse);
// }
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
resetData();
}
void populateFormValues() {
_serialNoController.text = _scannedAssetModel!.serialNo ?? '';
_assetNoController.text = _scannedAssetModel!.assetNumber ?? '';
// _scannedAssetModel?.supplier = SupplierDetails(
// suppliername: _scannedAssetModel?.supplierName,
// id: _scannedAssetModel?.supplierId,
// );
}
@override
@ -94,147 +95,206 @@ class _AssetInventoryFormViewState extends State<AssetInventoryFormView> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (widget.sessionTypeValue == 1 || widget.sessionTypeValue == 2) ...[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
'Not Registered'.addTranslation.heading5(context),
AdvancedSwitch(
controller: registeredController,
activeColor: AppColor.green50.withOpacity(0.5),
inactiveColor: AppColor.neutral10,
thumb: CircleAvatar(backgroundColor: isRegistered == true ? AppColor.green50 : AppColor.neutral20),
borderRadius: const BorderRadius.all(Radius.circular(30)),
width: 42.toScreenWidth,
height: 24.toScreenHeight,
onChanged: (value) {
isRegistered = value;
resetData();
setState(() {});
},
disabledOpacity: 1,
),
],
),
16.height,
],
if ((!isRegistered && widget.sessionTypeValue == 1) || (widget.sessionTypeValue == 3) || (!isRegistered && widget.sessionTypeValue == 2)) ...[
AssetPicker(
device: _pickedAsset,
showLoading: false,
labelColor: AppColor.white936,
iconColor: AppColor.neutral120,
label: 'Scan Asset'.addTranslation,
borderColor: AppColor.white936,
buttonColor: Colors.white,
enablePickManually: false,
showAssetInfo: false,
showBorder: true,
onPick: (asset) async {
_pickedAsset = asset;
//TODO set value to model .
// 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;
// }
resetData();
setState(() {});
if (asset.assetNumber != null) {
searchAsset(assetNo: asset.assetNumber!);
}
}),
12.height,
AppTextFormField(
labelText: context.translation.assetNo,
backgroundColor: AppColor.fieldBgColor(context),
textAlign: TextAlign.center,
controller: _assetNoController,
showShadow: false,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
style: Theme.of(context).textTheme.titleMedium,
),
12.height,
],
if (((!isRegistered && widget.sessionTypeValue == 2)))
AppFilledButton(
label: 'Search Asset'.addTranslation,
onPressed: () async {
resetData(isScanned: false);
setState(() {});
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SearchAssetView(
sessionId: widget.assetInventoryModel?.sessionId ?? 0,
))).then((value) {
if (value != null) {
_pickedAssetModel = value;
// _pickedAssetModel?.assetNumber = _scannedAssetModel?.assetNumber;
// _pickedAssetModel?.assetId = _scannedAssetModel?.assetId;
// _pickedAssetModel?.status = _scannedAssetModel?.status;
_scannedAssetModel = _scannedAssetModel?.mergeWith(_pickedAssetModel) ?? _pickedAssetModel;
populateFormValues();
setState(() {});
}
///Need to assign the values
});
},
).paddingOnly(bottom: 12),
AppTextFormField(
labelText: context.translation.serialNo,
backgroundColor: AppColor.fieldBgColor(context),
controller: _serialNoController,
textAlign: TextAlign.center,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
onChange: (value) {
if (value != _scannedAssetModel?.serialNo) {
_scannedAssetModel?.newSerialNo = value;
// setState(() {});
}
},
style: Theme.of(context).textTheme.titleMedium,
),
12.height,
AutoCompleteGenericField<SparePartsWorkOrders>(
LookUpAutoCompleteField(
clearAfterPick: false,
label: 'Asset Name'.addTranslation,
displayString: (item) => "",
onSearch: (query) async {
// final provider = Provider.of<PartsProvider>(context, listen: false);
// final list = await provider.getPartsList(partName: query);
// return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList();
return [];
forAssetName: true,
onChanged: (value) {
_scannedAssetModel?.newAssetNameId = null;
_scannedAssetModel?.newAssetNameText = value;
},
initialValue: '',
// initialValue: model.partCatalogItem?.partNumber ?? "",
onPick: (part) {
initialValue: _scannedAssetModel?.assetName ?? "",
label: 'Asset Name'.addTranslation,
onPick: (value) {
_scannedAssetModel?.newAssetNameText = null;
_scannedAssetModel?.assetName = value.name;
_scannedAssetModel?.newAssetNameId = value.id;
setState(() {});
},
),
12.height,
//Asset Name..
AutoCompleteGenericField<SparePartsWorkOrders>(
LookUpAutoCompleteField(
clearAfterPick: false,
isManufacturer: true,
initialValue: _scannedAssetModel?.manufacturer ?? "",
label: 'Manufacturer'.addTranslation,
displayString: (item) => "",
onSearch: (query) async {
// final provider = Provider.of<PartsProvider>(context, listen: false);
// final list = await provider.getPartsList(partName: query);
// return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList();
return [];
onChanged: (value) {
_scannedAssetModel?.newManufacturerId = null;
_scannedAssetModel?.newManufacturerName = value;
},
initialValue: '',
// initialValue: model.partCatalogItem?.partNumber ?? "",
onPick: (part) {
onPick: (value) {
_scannedAssetModel?.newManufacturerName = null;
_scannedAssetModel?.manufacturer = value.name;
_scannedAssetModel?.newManufacturerId = value.id;
setState(() {});
},
),
12.height,
//manufacture..
AutoCompleteGenericField<SparePartsWorkOrders>(
LookUpAutoCompleteField(
clearAfterPick: false,
isManufacturer: false,
initialValue: _scannedAssetModel?.model ?? "",
label: 'Model'.addTranslation,
displayString: (item) => "",
onSearch: (query) async {
// final provider = Provider.of<PartsProvider>(context, listen: false);
// final list = await provider.getPartsList(partName: query);
// return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList();
return [];
onChanged: (value) {
_scannedAssetModel?.newModelId = null;
_scannedAssetModel?.newModelName = value;
},
initialValue: '',
// initialValue: model.partCatalogItem?.partNumber ?? "",
onPick: (part) {
onPick: (value) {
_scannedAssetModel?.newModelName = null;
_scannedAssetModel?.model = value.name;
_scannedAssetModel?.newModelId = value.id;
setState(() {});
},
),
12.height,
//model..
AutoCompleteGenericField<SparePartsWorkOrders>(
LookUpAutoCompleteField(
clearAfterPick: false,
label: 'Asset Name'.addTranslation,
displayString: (item) => "",
onSearch: (query) async {
// final provider = Provider.of<PartsProvider>(context, listen: false);
// final list = await provider.getPartsList(partName: query);
// return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList();
return [];
forSupplier: true,
initialValue: _scannedAssetModel?.supplierName ?? "",
label: context.translation.supplier,
onChanged: (value) {
_scannedAssetModel?.newSupplierId = null;
_scannedAssetModel?.newSupplierName = value;
},
initialValue: '',
// initialValue: model.partCatalogItem?.partNumber ?? "",
onPick: (part) {
setState(() {});
},
),
12.height,
SingleItemDropDownMenu<SupplierDetails, VendorProvider>(
context: context,
title: context.translation.supplier,
backgroundColor: AppColor.fieldBgColor(context),
initialValue: null,
showAsBottomSheet: true,
showShadow: false,
showCancel: true,
onSelect: (supplier) {
onPick: (value) {
_scannedAssetModel?.newSupplierName = null;
_scannedAssetModel?.supplierName = value.name;
_scannedAssetModel?.newSupplierId = value.id;
setState(() {});
},
),
// SingleItemDropDownMenu<SupplierDetails, VendorProvider>(
// context: context,
// title: context.translation.supplier,
// backgroundColor: AppColor.fieldBgColor(context),
// initialValue: _scannedAssetModel?.supplier,
// showAsBottomSheet: true,
// showShadow: false,
// showCancel: true,
// onSelect: (supplier) {
// _scannedAssetModel?.supplier = supplier;
// _scannedAssetModel?.newSupplierId = supplier?.id;
// _scannedAssetModel?.newSupplierName = supplier?.name;
// setState(() {});
// },
// ),
12.height,
siteInfoContainer(label: context.translation.site, value:widget.assetLocation?.site?.name??'-' ),
siteInfoContainer(label: context.translation.site, value: _scannedAssetModel?.siteName ?? '-'),
12.height,
siteInfoContainer(label: context.translation.building, value:widget.assetLocation?.building?.name??'-' ),
siteInfoContainer(label: context.translation.building, value: _scannedAssetModel?.buildingName ?? '-'),
12.height,
siteInfoContainer(label: context.translation.floor, value:widget.assetLocation?.floor?.name??'-' ),
siteInfoContainer(label: context.translation.floor, value: _scannedAssetModel?.floorName ?? '-'),
12.height,
siteInfoContainer(label: context.translation.department, value:widget.assetLocation?.department?.name??'-' ),
siteInfoContainer(label: context.translation.department, value: _scannedAssetModel?.departmentName ?? '-'),
12.height,
siteInfoContainer(label: context.translation.room, value:widget.assetLocation?.room?.name??'-' ),
siteInfoContainer(label: context.translation.room, value: _scannedAssetModel?.roomName ?? '-'),
12.height,
classificationWidget(label: 'Found'),
if (_scannedAssetModel?.status != null && _scannedAssetModel!.status!.isNotEmpty) classificationWidget(label: _scannedAssetModel?.status),
12.height,
Text(
'Asset Photo'.addTranslation,
@ -269,8 +329,10 @@ class _AssetInventoryFormViewState extends State<AssetInventoryFormView> {
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
showShadow: false,
controller: _remarksController,
onSaved: (text) {
_assetInventoryModel.remarks = text;
_scannedAssetModel?.remarks = text;
setState(() {});
},
),
// 100.height,
@ -288,21 +350,41 @@ class _AssetInventoryFormViewState extends State<AssetInventoryFormView> {
);
}
Future<void> searchAsset({required String assetNo}) async {
AssetInventoryProvider provider = Provider.of<AssetInventoryProvider>(context, listen: false);
Map<String, dynamic> payload = {
"assetNumber": assetNo,
"sessionId": widget.assetInventoryModel?.sessionId,
"siteId": widget.assetInventoryModel?.site?.id,
"buildingId": widget.assetInventoryModel?.building?.id,
"floorId": widget.assetInventoryModel?.floor?.id,
"departmentId": widget.assetInventoryModel?.department?.id,
"roomId": widget.assetInventoryModel?.room?.id,
};
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
_scannedAssetModel = await provider.searchAsset(payload: payload);
Navigator.pop(context);
if (_scannedAssetModel != null) {
populateFormValues();
}
setState(() {});
}
Widget siteInfoContainer({required String label , required String value}){
Widget siteInfoContainer({required String label, required String value}) {
//TODO may be need to hide value for if empty or null .
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth,vertical: 12.toScreenHeight),
decoration: BoxDecoration(
color: AppColor.neutral80,
borderRadius: BorderRadius.circular(8)
),
padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth, vertical: 12.toScreenHeight),
decoration: BoxDecoration(color: AppColor.neutral80, borderRadius: BorderRadius.circular(8)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label,style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500)),
Text(value,style:Theme.of(context).textTheme.bodyLarge,),
Text(label, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500)),
Text(
value,
style: Theme.of(context).textTheme.bodyLarge,
),
],
),
);
@ -327,27 +409,53 @@ class _AssetInventoryFormViewState extends State<AssetInventoryFormView> {
);
}
Future<bool> validateRequest() async {
if (_pickedAsset == null) {
await Fluttertoast.showToast(msg: "Please Select Asset");
return false;
void _onSubmit() async {
AssetInventoryProvider assetInventoryProvider = Provider.of<AssetInventoryProvider>(context, listen: false);
_formKey.currentState!.save();
_scannedAssetModel?.sessionId = widget.assetInventoryModel?.sessionId;
_scannedAssetModel?.siteId = widget.assetInventoryModel?.site?.id;
_scannedAssetModel?.buildingId = widget.assetInventoryModel?.building?.id;
_scannedAssetModel?.floorId = widget.assetInventoryModel?.floor?.id;
_scannedAssetModel?.departmentId = widget.assetInventoryModel?.department?.id;
_scannedAssetModel?.roomId = widget.assetInventoryModel?.room?.id;
_scannedAssetModel?.isNotRegistered = isRegistered;
if (attachments.isNotEmpty) {
String? photoName = attachments.first.name;
String fileName = ServiceRequestUtils.isLocalUrl(photoName ?? '') ? ("${photoName ?? ''.split("/").last}|${base64Encode(File(photoName ?? '').readAsBytesSync())}") : photoName ?? '';
_scannedAssetModel?.photo = fileName;
}
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
assetInventoryProvider.saveAssetInSession(model: _scannedAssetModel).then((success) {
///Need to use push and remove until...
Navigator.pop(context);
if (success) {
// Navigator.pop(context);
// Navigator.pop(context);
/// need to confirm need to call this ...
AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
allRequestsProvider.reset();
allRequestsProvider.getAllRequests(context, typeTransaction: 8);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (contxt) => SiteInformationView(
sessionModel: SessionModel(id: int.tryParse(widget.assetInventoryModel?.sessionId?.toString() ?? '') ?? 0),
)));
} else {
log('api error...');
}
});
}
void resetData({bool isScanned = true}) {
if (isScanned) {
_scannedAssetModel = AssetInventoryModel();
}
// 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;
_assetNoController.clear();
_serialNoController.clear();
_pickedAssetModel = AssetInventoryModel();
attachments.clear();
_remarksController.clear();
registeredController?.dispose();
}
}

@ -10,7 +10,7 @@ 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/asset_inventory_module/pages/asset_inventory_site_information_view.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';
@ -121,6 +121,7 @@ class _AssetInventoryPageState extends State<AssetInventoryPage> {
}
Future<void> _scanAsset({required AssetInventoryProvider provider}) async {
Navigator.push(context, MaterialPageRoute(builder: (contxt) => PickSiteInformationView(sessionModel: provider.sessionModel ?? SessionModel())));
provider.siteFilterAssetList.clear();
Navigator.push(context, MaterialPageRoute(builder: (contxt) => SiteInformationView(sessionModel: provider.sessionModel ?? SessionModel())));
}
}

@ -1,77 +1,131 @@
import 'dart:developer';
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/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/modules/asset_inventory_module/provider/asset_inventory_provider.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/views/widgets/loaders/lazy_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import 'asset_detail_card_view.dart';
class AssetInventoryScanAssetView extends StatefulWidget {
int sessionId ;
AssetInventoryScanAssetView({Key? key,required this.sessionId}) : super(key: key);
int sessionId;
AssetInventoryScanAssetView({Key? key, required this.sessionId}) : super(key: key);
@override
State<AssetInventoryScanAssetView> createState() => _AssetInventoryScanAssetViewState();
}
class _AssetInventoryScanAssetViewState extends State<AssetInventoryScanAssetView> {
late AssetInventoryProvider assetInventoryProvider;
@override
void initState() {
assetInventoryProvider = Provider.of<AssetInventoryProvider>(context,listen:false);
assetInventoryProvider = Provider.of<AssetInventoryProvider>(context, listen: false);
super.initState();
}
Future<void> getAssetList({bool reset = false}) async {
if (reset) {
assetInventoryProvider.pageNo = 1;
assetInventoryProvider.assetInventoryResponse = null;
}
Future<void> getAssetList({bool loadMore = false}) async {
await assetInventoryProvider.getAssetsInSession(
sessionId: widget.sessionId,
loadMore: loadMore,
);
}
@override
@override
Widget build(BuildContext context) {
return Consumer<AssetInventoryProvider>(
builder: (context, provider, _) {
if (provider.isLoading && provider.assetInventoryResponse == null) {
//TODO need use existing loader if found..
return const Center(child: CircularProgressIndicator());
}
final assets = provider.assetInventoryResponse?.assetList ?? [];
if (assets.isEmpty) {
return const Center(child: NoDataFound());
}
return LazyLoading(
nextPage: provider.nextPage,
onLazyLoad: () async {
await getAssetList();
return NotificationListener<ScrollNotification>(
onNotification: (scrollInfo) {
if (!provider.isNextPageLoading &&
provider.nextPage &&
scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
getAssetList(loadMore: true);
}
return false;
},
child: ListView.separated(
padding: const EdgeInsets.all(16),
itemCount: assets.length + (provider.isNextPageLoading ? 1 : 0),
itemBuilder: (context, index) {
return AssetDetailCardView(assetInventoryModel: assets[index]);
if (index == assets.length) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Center(child: CircularProgressIndicator()),
);
}
return AssetDetailCardView(
assetInventoryModel: assets[index],
onDeletePress: () async {
await provider.deleteAssetISession(id: assets[index].id ?? 0).then((success) async {
if (success) {
await provider.getAssetsInSession(sessionId: widget.sessionId);
}
});
},
);
},
separatorBuilder: (context, index) => 12.height,
itemCount: assets.length,
),
);
},
);
}
void _addAsset(BuildContext context) {
//TODO need to confirm navigation...
Navigator.push(context, MaterialPageRoute(builder: (contxt) => AssetInventoryFormView()));
}
// Widget build(BuildContext context) {
// return Consumer<AssetInventoryProvider>(
// builder: (context, provider, _) {
// if (provider.isLoading && provider.assetInventoryResponse == null) {
// //TODO need use existing loader if found..
// return const Center(child: CircularProgressIndicator());
// }
// final assets = provider.assetInventoryResponse?.assetList ?? [];
// if (assets.isEmpty) {
// return const Center(child: NoDataFound());
// }
// return LazyLoading(
// nextPage: provider.nextPage,
// onLazyLoad: () async {
// log('Loading next page...');
// await getAssetList(loadMore: true);
// },
// child: ListView.separated(
// padding: const EdgeInsets.all(16),
// itemBuilder: (context, index) {
// if (index == assets.length) {
// // bottom loader
// return const Padding(
// padding: EdgeInsets.symmetric(vertical: 16),
// child: Center(child: CircularProgressIndicator()),
// );
// }
// return AssetDetailCardView(
// assetInventoryModel: assets[index],
// onDeletePress: () async {
// await provider.deleteAssetISession(id: assets[index].id ?? 0).then((success) async {
// if (success) {
// await provider.getAssetsInSession(sessionId: widget.sessionId);
// }
// });
// },
// );
// },
// separatorBuilder: (context, index) => 12.height,
// itemCount: assets.length + (provider.nextPage ? 1 : 0),
// ),
// );
// },
// );
// }
}

@ -0,0 +1,311 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/all_requests_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/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/site.dart';
import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_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/asset_inventory_module/provider/asset_inventory_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/app_lazy_loading.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/loading_list_notifier.dart';
import 'package:test_sa/views/widgets/loaders/lazy_loading.dart';
class SiteInformationView extends StatefulWidget {
SessionModel sessionModel;
SiteInformationView({Key? key, required this.sessionModel}) : super(key: key);
@override
State<SiteInformationView> createState() => _SiteInformationViewState();
}
class _SiteInformationViewState extends State<SiteInformationView> {
AssetInventoryModel assetInventoryModel = AssetInventoryModel();
bool showMarkAsComplete = false;
@override
void initState() {
super.initState();
}
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
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: SafeArea(
child: Column(
children: [
ListView(
padding: const EdgeInsets.only(left: 16, right: 16, top: 16),
children: [
siteInfoCard(context, widget.sessionModel),
12.height,
assetDetailList(),
8.height,
],
).expanded,
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
buttonColor: AppColor.primary10,
label: 'Add Asset'.addTranslation,
onPressed: () => _addAsset(),
// buttonColor: AppColor.primary10,
),
),
if (showMarkAsComplete)
AppFilledButton(
buttonColor: AppColor.green70,
label: 'Mark as completed'.addTranslation,
onPressed: () => _markAsCompleted(),
// buttonColor: AppColor.primary10,
).paddingOnly(start: 16, end: 16),
// FooterActionButton.footerContainer(
// context: context,
// child: AppFilledButton(
// buttonColor: AppColor.green70,
// label: 'Mark as completed'.addTranslation,
// onPressed: () => _markAsCompleted(),
// // buttonColor: AppColor.primary10,
// ),
// ),
],
),
));
}
void _addAsset() async {
if (await validateRequest()) {
assetInventoryModel.sessionId = widget.sessionModel.id;
Navigator.push(
context,
MaterialPageRoute(
builder: (contxt) => AssetInventoryFormView(
assetInventoryModel: assetInventoryModel,
sessionTypeValue: widget.sessionModel.sessionTypeValue,
)));
}
}
void _markAsCompleted() async {
if (await validateRequest()) {
assetInventoryModel.sessionId = widget.sessionModel.id;
AssetInventoryProvider provider = Provider.of<AssetInventoryProvider>(context, listen: false);
Map<String, dynamic> payload = {
"sessionId": widget.sessionModel.id,
"siteId": assetInventoryModel.site?.id,
"buildingId": assetInventoryModel.building?.id,
"floorId": assetInventoryModel.floor?.id,
"departmentId": assetInventoryModel.department?.id,
"roomId": assetInventoryModel.room?.id,
};
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
await provider.markAsComplete(payload: payload).then((success) {
Navigator.pop(context);
log('success $success');
if (success) {
///TODO need to confirm need to call this or not ..
// AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
// allRequestsProvider.reset();
// allRequestsProvider.getAllRequests(context, typeTransaction: 8);
///Need to call push and remove until...
Navigator.pop(context);
Navigator.pop(context);
}
});
}
}
Widget assetDetailList() {
return Consumer<AssetInventoryProvider>(
builder: (context, provider, _) {
if (provider.isLoading) {
return SizedBox(height: 300.toScreenHeight, child: const CircularProgressIndicator(color: AppColor.primary10).center);
}
final assets = provider.siteFilterAssetList;
return NotificationListener<ScrollNotification>(
onNotification: (scrollInfo) {
if (!provider.isNextPageLoading && provider.nextPage && scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
getAssetFilteredList(loadMore: true);
}
return false;
},
child: ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return AssetDetailCardView(
assetInventoryModel: assets[index],
onDeletePress: () async {
log('Delete icon press');
await provider.deleteAssetISession(id: assets[index].id ?? 0).then((success) async {
if (success) {
await getAssetFilteredList();
await provider.getAssetsInSession(
sessionId: widget.sessionModel.id ?? 0,
);
}
});
},
);
},
separatorBuilder: (context, index) => 12.height,
itemCount: assets.length,
),
);
},
);
}
Widget siteInfoCard(BuildContext context, SessionModel sessionModel) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
12.height,
SingleItemDropDownMenu<Site, NullableLoadingProvider>(
context: context,
title: context.translation.site,
initialValue: assetInventoryModel.site,
showShadow: false,
staticData: sessionModel.assetInventorySites,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
onSelect: (value) {
assetInventoryModel.site = value;
assetInventoryModel.building = null;
assetInventoryModel.floor = null;
assetInventoryModel.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Building, NullableLoadingProvider>(
context: context,
title: context.translation.building,
initialValue: assetInventoryModel.building,
showShadow: false,
showAsBottomSheet: true,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetInventoryModel.site?.buildings?.isNotEmpty ?? false,
staticData: assetInventoryModel.site?.buildings ?? [],
onSelect: (value) {
assetInventoryModel.building = value;
assetInventoryModel.floor = null;
assetInventoryModel.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
context: context,
title: context.translation.floor,
showShadow: false,
showAsBottomSheet: true,
initialValue: assetInventoryModel.floor,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetInventoryModel.building?.floors?.isNotEmpty ?? false,
staticData: assetInventoryModel.building?.floors ?? [],
onSelect: (value) {
assetInventoryModel.floor = value;
assetInventoryModel.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Department, NullableLoadingProvider>(
context: context,
title: context.translation.department,
showShadow: false,
showAsBottomSheet: true,
initialValue: assetInventoryModel.department,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetInventoryModel.floor?.departments?.isNotEmpty ?? false,
staticData: assetInventoryModel.floor?.departments ?? [],
onSelect: (value) {
assetInventoryModel.department = value;
assetInventoryModel.room = null;
showMarkAsComplete = true;
setState(() {});
getAssetFilteredList();
},
),
8.height,
SingleItemDropDownMenu<Rooms, NullableLoadingProvider>(
context: context,
title: context.translation.room,
showShadow: false,
showAsBottomSheet: true,
initialValue: assetInventoryModel.room,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetInventoryModel.department?.rooms?.isNotEmpty ?? false,
staticData: assetInventoryModel.department?.rooms ?? [],
onSelect: (value) {
assetInventoryModel.room = value;
setState(() {});
if (assetInventoryModel.room != null) {
getAssetFilteredList();
}
},
),
8.height,
],
).toShadowContainer(context);
}
Future<bool> validateRequest() async {
if (assetInventoryModel.site == null) {
await Fluttertoast.showToast(msg: "Please Select Site");
return false;
}
if (assetInventoryModel.building == null) {
await Fluttertoast.showToast(msg: "Please Select Building");
return false;
}
if (assetInventoryModel.floor == null) {
await Fluttertoast.showToast(msg: "Please Select Floor");
return false;
}
if (assetInventoryModel.department == null) {
await Fluttertoast.showToast(msg: "Please Select Department");
return false;
}
return true;
}
Future<void> getAssetFilteredList({bool loadMore = false}) async {
AssetInventoryProvider provider = Provider.of<AssetInventoryProvider>(context, listen: false);
Map<String, dynamic> payload = {
"sessionId": widget.sessionModel.id,
"siteId": assetInventoryModel.site?.id,
"buildingId": assetInventoryModel.building?.id,
"floorId": assetInventoryModel.floor?.id,
"departmentId": assetInventoryModel.department?.id,
"roomId": assetInventoryModel.room?.id,
};
await provider.getInventoryDetailsByFilter(payload: payload, loadMore: loadMore);
}
}

@ -47,10 +47,9 @@ class InventorySessionCard extends StatelessWidget {
),
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),
infoWidget(label: 'Type'.addTranslation, value: requestData?.sessionType, context: context),
infoWidget(label: 'Assets'.addTranslation, value: requestData?.numberOfAssets!=null? requestData?.numberOfAssets.toString():'-', context: context),
infoWidget(label: 'Sites'.addTranslation, value: requestData?.numberOfSites!=null? requestData?.numberOfSites.toString():'-', context: context),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
@ -98,11 +97,9 @@ class InventorySessionCard extends StatelessWidget {
),
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),
infoWidget(label: 'Type'.addTranslation, value: requestDetails?.sessionType, context: context),
infoWidget(label: 'Assets'.addTranslation, value: requestDetails?.numberOfAssets!=null? requestDetails?.numberOfAssets.toString():'-', context: context),
infoWidget(label: 'Sites'.addTranslation, value: requestDetails?.numberOfSites!=null? requestDetails?.numberOfSites.toString():'-', context: context),
8.height,
Row(
mainAxisSize: MainAxisSize.min,

@ -1,257 +0,0 @@
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/modules/asset_inventory_module/models/asset_inventory_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/asset_inventory_module/provider/asset_inventory_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/loading_list_notifier.dart';
import 'package:test_sa/views/widgets/loaders/lazy_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import '../../../models/new_models/site.dart';
class PickSiteInformationView extends StatefulWidget {
SessionModel sessionModel;
PickSiteInformationView({Key? key, required this.sessionModel}) : super(key: key);
@override
State<PickSiteInformationView> createState() => _PickSiteInformationViewState();
}
class _PickSiteInformationViewState extends State<PickSiteInformationView> {
// TODO need to use only one model AssetInventoryModel everywhere after completing flow .
Asset assetLocation = Asset();
void _onSave() async {}
@override
void initState() {
super.initState();
}
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
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: [
ListView(
padding: const EdgeInsets.only(left: 16, right: 16, top: 16),
children: [
siteInfoCard(context, widget.sessionModel),
12.height,
//TODO need to implement when api is working ...
// assetDetailList(),
// 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,
],
).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) => AssetInventoryFormView(
assetLocation: assetLocation,
)));
}
Future<void> getAssetList({bool reset = false}) async {
AssetInventoryProvider assetInventoryProvider = Provider.of<AssetInventoryProvider>(context,listen: false);
if (reset) {
assetInventoryProvider.pageNo = 1;
assetInventoryProvider.assetInventoryResponse = null;
}
await assetInventoryProvider.getAssetsInSession(
sessionId: widget.sessionModel.id??0,
);
}
Widget assetDetailList() {
return Consumer<AssetInventoryProvider>(
builder: (context, provider,child) {
return Consumer<AssetInventoryProvider>(
builder: (context, provider, _) {
if (provider.isLoading && provider.assetInventoryResponse == null) {
//TODO need use existing loader if found..
return const Center(child: CircularProgressIndicator());
}
final assets = provider.assetInventoryResponse?.assetList ?? [];
if (assets.isEmpty) {
return const Center(child: NoDataFound());
}
return LazyLoading(
nextPage: provider.nextPage,
onLazyLoad: () async {
await getAssetList();
},
child: ListView.separated(
padding: const EdgeInsets.all(16),
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return AssetDetailCardView(assetInventoryModel: assets[index]);
},
separatorBuilder: (context, index) => 12.height,
itemCount: assets.length,
),
);
},
);
}
);
}
Widget siteInfoCard(BuildContext context, SessionModel sessionModel) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
12.height,
SingleItemDropDownMenu<Site, NullableLoadingProvider>(
context: context,
title: context.translation.site,
initialValue: assetLocation.site,
showShadow: false,
staticData: sessionModel.assetInventorySites,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
onSelect: (value) {
assetLocation.site = value;
assetLocation.building = null;
assetLocation.floor = null;
assetLocation.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Building, NullableLoadingProvider>(
context: context,
title: context.translation.building,
initialValue: assetLocation.building,
showShadow: false,
showAsBottomSheet: true,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetLocation.site?.buildings?.isNotEmpty ?? false,
staticData: assetLocation.site?.buildings ?? [],
onSelect: (value) {
assetLocation.building = value;
assetLocation.floor = null;
assetLocation.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
context: context,
title: context.translation.floor,
showShadow: false,
showAsBottomSheet: true,
initialValue: assetLocation.floor,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetLocation.building?.floors?.isNotEmpty ?? false,
staticData: assetLocation.building?.floors ?? [],
onSelect: (value) {
assetLocation.floor = value;
assetLocation.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Department, NullableLoadingProvider>(
context: context,
title: context.translation.department,
showShadow: false,
showAsBottomSheet: true,
initialValue: assetLocation.department,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetLocation.floor?.departments?.isNotEmpty ?? false,
staticData: assetLocation.floor?.departments ?? [],
onSelect: (value) {
assetLocation.department = value;
assetLocation.room = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Rooms, NullableLoadingProvider>(
context: context,
title: context.translation.room,
showShadow: false,
showAsBottomSheet: true,
initialValue: assetLocation.room,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetLocation.department?.rooms?.isNotEmpty ?? false,
staticData: assetLocation.department?.rooms ?? [],
onSelect: (value) {
assetLocation.room = value;
setState(() {});
},
),
8.height,
],
).toShadowContainer(context);
}
Future<bool> validateRequest() async {
if (assetLocation.site == null) {
await Fluttertoast.showToast(msg: "Please Select Site");
return false;
}
if (assetLocation.building == null) {
await Fluttertoast.showToast(msg: "Please Select Building");
return false;
}
if (assetLocation.floor == null) {
await Fluttertoast.showToast(msg: "Please Select Floor");
return false;
}
if (assetLocation.department == null) {
await Fluttertoast.showToast(msg: "Please Select Department");
return false;
}
return true;
}
}

@ -0,0 +1,276 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/urls.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/asset_inventory_model.dart';
import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/equipment/asset_item_listview.dart';
import 'package:test_sa/views/widgets/horizontal_list_widget.dart';
import 'package:test_sa/views/widgets/loaders/lazy_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import '../../../models/device/asset.dart';
import '../../../models/device/asset_search.dart';
import '../../../new_views/app_style/app_color.dart';
import '../../../new_views/common_widgets/app_lazy_loading.dart';
import '../../../new_views/common_widgets/custom_app_bar.dart';
class SearchAssetView extends StatefulWidget {
static const String id = "asset_search_view";
final num sessionId;
const SearchAssetView({Key? key, required this.sessionId}) : super(key: key);
@override
State<SearchAssetView> createState() => _SearchAssetViewState();
}
class _SearchAssetViewState extends State<SearchAssetView> {
int _selectedIndex = 0;
DeviceSearch? search;
late TextEditingController _searchController;
late AssetInventoryProvider _assetInventoryProvider;
final List<AssetInventoryModel> _searchableList = [];
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
bool _isFirst = true;
@override
void initState() {
_searchController = TextEditingController();
super.initState();
}
@override
void dispose() {
_searchController.dispose();
_assetInventoryProvider.searchReset();
super.dispose();
}
@override
Widget build(BuildContext context) {
List<String> searchBy = [
context.translation.assetName,
context.translation.model,
context.translation.manufacture,
context.translation.snNumber,
context.translation.siteName,
// 'Building Name'.addTranslation,
// 'Floor Name'.addTranslation,
'Department Name'.addTranslation,
///need to check if want to add more filters
];
_assetInventoryProvider = Provider.of<AssetInventoryProvider>(context, listen: false);
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: CustomAppBar(
title: context.translation.searchAsset,
),
body: Column(
children: [
HorizontalListWidget(
list: searchBy,
callBackFunction: (index) {
setState(() {
_selectedIndex = index;
});
},
).paddingOnly(top: 16, bottom: 0),
Form(
key: _formKey,
child: AppTextFormField(
controller: _searchController,
textInputAction: TextInputAction.search,
labelText: "${context.translation.searchBy} ${searchBy[_selectedIndex]}",
onAction: _search,
onChange: (text) {
_searchController.text = text;
_searchController.selection = TextSelection.fromPosition(TextPosition(offset: _searchController.text.length));
setState(() {});
},
onSaved: (value) {
setState(() {
search = DeviceSearch();
});
_setValue(value);
},
suffixIcon: IconButton(
icon: const Icon(Icons.search),
splashColor: Colors.transparent,
onPressed: _searchController.text.isNotEmpty ? _search : null,
color: AppColor.neutral20,
).paddingOnly(end: 0),
).paddingOnly(top: 16, start: 16, end: 16, bottom: 8),
),
Expanded(
child: _searchableList.isEmpty
? _isFirst
? const SizedBox()
: NoDataFound(message: context.translation.noDeviceFound)
: LazyLoading(
nextPage: _assetInventoryProvider.nextPage,
onLazyLoad: () async {
if (_searchController.text.isNotEmpty) {
await _assetInventoryProvider.getAssets(search: search, isSearchBy: true, sessionId: widget.sessionId);
setState(() {
_searchableList.clear();
_searchableList.addAll(_assetInventoryProvider.searchDevices);
});
}
},
child: Column(
children: [
ListView.separated(
itemCount: _searchableList.length,
separatorBuilder: (listContext, itemIndex) => 8.height,
padding: const EdgeInsets.all(16),
itemBuilder: (listContext, itemIndex) {
// bool isSelected = selectedAssets.contains(_searchableList[itemIndex].id!);
// String title = isSelected ? "UnSelect" : "Select";
return InventoryAssetItemListView(
device: _searchableList[itemIndex],
// isSelected: isSelected,
onPressed: (device) {
// Navigator.of(context).pop();
Navigator.of(context).pop(device);
},
// selectButton: Text(title, style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context))),
);
},
).expanded,
],
),
),
)
],
));
}
void _search() async {
FocusScope.of(context).unfocus();
_formKey.currentState!.save();
_assetInventoryProvider.searchReset();
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
await _assetInventoryProvider.getAssets(search: search, isSearchBy: true, sessionId: widget.sessionId);
setState(() {
_searchableList.clear();
_searchableList.addAll(_assetInventoryProvider.searchDevices);
_isFirst = false;
});
Navigator.pop(context);
}
_setValue(value) {
/// todo : check oracle code (no matched parameter)
/// //ontext.translation.assetName,
// context.translation.model,
// context.translation.manufacture,
// context.translation.snNumber,
// context.translation.siteName,
// // 'Building Name'.addTranslation,
// // 'Floor Name'.addTranslation,
// 'Department Name'.addTranslation,
switch (_selectedIndex) {
case 0:
search!.assetName = value;
break;
case 1:
search!.model = value;
break;
case 2:
search!.manufacturer = value;
break;
case 3:
search!.assetSerialNumber = value;
break;
case 4:
search!.site = value;
break;
case 5:
search!.department = value;
break;
default:
break;
}
}
// bool _showResetButton() {
// return (_searchController?.text?.isNotEmpty ?? false);
// }
}
class InventoryAssetItemListView extends StatelessWidget {
final AssetInventoryModel device;
final Function(AssetInventoryModel) onPressed;
final Widget? selectButton;
final bool isSelected;
const InventoryAssetItemListView({Key? key, required this.device, required this.onPressed, this.selectButton, this.isSelected = false}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 95,
height: 95,
decoration: ShapeDecoration(
color: context.isDark ? AppColor.neutral50 : AppColor.neutral30,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(device.photo != null ? URLs.getFileUrl(device.photo!)! : "https://www.lasteelcraft.com/images/no-image-available.png"),
)),
),
15.width,
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
device.assetName!.cleanupWhitespace.capitalizeFirstOfEach.heading6(context),
8.height,
"${context.translation.assetNumber} : ${device.assetNumber}".bodyText(context),
"${context.translation.modelName} : ${device.model}".cleanupWhitespace.capitalizeFirstOfEach.bodyText(context),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"${context.translation.serialNo} : ${device.serialNo}".bodyText(context).expanded,
4.width,
selectButton ??
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,
)
],
),
],
)
],
).expanded
],
).toShadowContainer(context, padding: 12, borderColor: isSelected ? AppColor.blueStatus(context) : Colors.transparent).onPress(() => onPressed(device));
}
}

@ -8,6 +8,9 @@ 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/device/asset.dart';
import 'package:test_sa/models/device/asset_search.dart';
import 'package:test_sa/models/lookup.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';
@ -26,11 +29,22 @@ import '../../../new_views/common_widgets/app_lazy_loading.dart';
class AssetInventoryProvider extends ChangeNotifier {
final pageItemNumber = 10;
final searchPageItemNumber = 10;
int pageNo = 1;
List<AssetInventoryModel> _devices = [];
List<AssetInventoryModel> _searchDevices = [];
List<AssetInventoryModel> get devices => _devices;
List<AssetInventoryModel> get searchDevices => _searchDevices;
SessionModel? sessionModel;
//TODO need to check i think don't need to create this obj
AssetInventoryResponse? assetInventoryResponse;
AssetInventoryResponse? siteFilterAssetResponse;
List<AssetInventoryModel> sessionAssetList = [];
List<AssetInventoryModel> siteFilterAssetList = [];
void reset() {
pageNo = 1;
@ -42,23 +56,29 @@ class AssetInventoryProvider extends ChangeNotifier {
int? stateCode;
bool isDetailLoading = false;
bool nextPage = true;
bool nextPage = false;
bool isNextPageLoading = false;
bool isLoading = false;
bool isAllAssetLoading = false;
Future getSessionById({required int id}) async {
void searchReset() {
stateCode = null;
_searchDevices = [];
}
Future<void> getSessionById({required int id}) async {
try {
sessionModel = SessionModel();
isLoading = true;
notifyListeners();
final response = await ApiManager.instance.get(URLs.getAssetInventoryById + "?assetInventoryId=$id");
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
sessionModel = SessionModel.fromJson(json.decode(response.body)["data"]);
} else {
sessionModel = null;
}
isLoading = false;
notifyListeners();
} catch (e) {
@ -72,49 +92,350 @@ class AssetInventoryProvider extends ChangeNotifier {
Future<int> getAssetsInSession({
required int sessionId,
bool loadMore = false,
}) async {
if (isLoading == true) return -2;
if (isLoading || isNextPageLoading) return -2;
if (loadMore) {
isNextPageLoading = true;
pageNo += 1;
} else {
isLoading = true;
pageNo = 1; // reset pagination
}
notifyListeners();
try {
final payload = {
"pageSize": pageItemNumber,
"pageNumber": pageNo,
"sessionId": sessionId,
};
final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
final Map<String, dynamic> jsonData = json.decode(response.body);
final newResponse = AssetInventoryResponse.fromJson(jsonData);
if (pageNo == 1) {
assetInventoryResponse = newResponse;
sessionAssetList = newResponse.assetList ?? [];
if (loadMore) {
assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []);
assetInventoryResponse?.totalRows = newResponse.totalRows;
} else {
sessionAssetList.addAll(newResponse.assetList ?? []);
assetInventoryResponse?.totalRows = newResponse.totalRows; // update total rows
assetInventoryResponse = newResponse;
}
if ((sessionAssetList.length) < (assetInventoryResponse?.totalRows ?? 0)) {
nextPage = true;
nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0);
} else {
nextPage = false;
}
isLoading = false;
isNextPageLoading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
isLoading = false;
isNextPageLoading = false;
stateCode = -1;
nextPage = false;
notifyListeners();
return -1;
}
}
///older code
// Future<int> getAssetsInSession({
// required int sessionId,
// bool loadMore = false,
// }) async {
// // if (isLoading || nextPage) return -2;
//
// if (loadMore) {
// nextPage = true;
// pageNo += 1;
// } else {
// isLoading = true;
// pageNo = 1; // reset pagination
// }
//
// notifyListeners();
// log('Fetching page: $pageNo');
//
// try {
// final payload = {
// "pageSize": pageItemNumber,
// "pageNumber": pageNo,
// "sessionId": sessionId,
// };
//
// final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload);
// stateCode = response.statusCode;
//
// if (response.statusCode >= 200 && response.statusCode < 300) {
// final Map<String, dynamic> jsonData = json.decode(response.body);
// final newResponse = AssetInventoryResponse.fromJson(jsonData);
//
// if (loadMore) {
// assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []);
// assetInventoryResponse?.totalRows = newResponse.totalRows;
// } else {
// assetInventoryResponse = newResponse;
// }
//
// nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0);
// }
//
// isLoading = false;
// nextPage = false;
// notifyListeners();
// return response.statusCode;
// } catch (error) {
// isLoading = false;
// nextPage = false;
// stateCode = -1;
// notifyListeners();
// return -1;
// }
// }
Future<int> getInventoryDetailsByFilter({
required Map<String, dynamic> payload,
bool loadMore = false,
}) async {
if (isLoading || isNextPageLoading) return -2;
if (loadMore) {
isNextPageLoading = true;
pageNo += 1;
} else {
sessionAssetList = [];
isLoading = true;
pageNo = 1;
}
notifyListeners();
log('Fetching inventory page: $pageNo');
try {
final paginatedPayload = {
...payload,
"pageSize": pageItemNumber,
"pageNumber": pageNo,
};
final response = await ApiManager.instance.post(URLs.getInventoryDetailsByFilter, body: paginatedPayload);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
final Map<String, dynamic> jsonData = json.decode(response.body);
final newResponse = AssetInventoryResponse.fromJson(jsonData);
if (loadMore) {
siteFilterAssetList.addAll(newResponse.assetList ?? []);
siteFilterAssetResponse?.totalRows = newResponse.totalRows;
} else {
siteFilterAssetResponse = newResponse;
siteFilterAssetList = newResponse.assetList ?? [];
}
nextPage = (siteFilterAssetList.length) < (siteFilterAssetResponse?.totalRows ?? 0);
} else {
siteFilterAssetList = [];
nextPage = false;
}
isLoading = false;
isNextPageLoading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
isLoading = false;
isNextPageLoading = false;
nextPage = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
Future<AssetInventoryModel?> searchAsset({
required Map<String, dynamic> payload,
}) async {
isLoading = true;
try {
final response = await ApiManager.instance.post(URLs.searchAsset, body: payload);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
final Map<String, dynamic> jsonData = json.decode(response.body)["data"];
AssetInventoryModel model = AssetInventoryModel.fromJson(jsonData);
log('model json ${model.toJson()}');
isLoading = false;
notifyListeners();
return model;
} else {
isLoading = false;
notifyListeners();
return null;
}
} catch (error) {
isLoading = false;
stateCode = -1;
notifyListeners();
return null;
}
}
Future<bool> saveAssetInSession({
AssetInventoryModel? model,
}) async {
isLoading = true;
try {
log('payload i got is ${model?.toJson()}');
final response = await ApiManager.instance.post(URLs.saveAssetInSession, body: model?.toJson() ?? {});
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
isLoading = false;
notifyListeners();
return true;
} else {
isLoading = false;
notifyListeners();
return false;
}
} catch (error) {
isLoading = false;
notifyListeners();
return false;
}
}
Future<bool> deleteAssetISession({required num id}) async {
try {
isLoading = true;
notifyListeners();
final response = await ApiManager.instance.get(URLs.deleteAssetInSession + "?id=$id");
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
isLoading = false;
notifyListeners();
return true;
}
isLoading = false;
notifyListeners();
return false;
} catch (e) {
log("Delete Asset [error] : $e");
isLoading = false;
notifyListeners();
return false;
}
}
Future<List<Lookup>> getAutoCompleteDetails({
bool? isManufacturer,
String? query,
int type = 0,
}) async {
try {
String url = '';
switch (type) {
//for model and manufacturer..
case 0:
url = URLs.getManufacturerOrModelAutoComplete;
break;
//for asset name..
case 1:
url = URLs.searchAssetName;
break;
//for supplier...
case 2:
url = URLs.getSuppliersAutoCompleteInventory;
break;
default:
url = URLs.getManufacturerOrModelAutoComplete;
}
final queryParams = <String, String>{};
if (isManufacturer != null && type == 0) {
queryParams['isManufacturer'] = isManufacturer.toString();
}
if (query != null && query.isNotEmpty) {
queryParams['searchText'] = query;
}
if (queryParams.isNotEmpty) {
url += '?${Uri(queryParameters: queryParams).query}';
}
final response = await ApiManager.instance.get(url);
List<Lookup> list = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
final data = json.decode(response.body)["data"];
list = (data as List).map((e) => Lookup.fromJson(e)).toList();
}
return list;
} catch (error) {
log('error $error');
return [];
}
}
Future<int> getAssets({DeviceSearch? search, bool isQr = false, bool isSearchBy = false, num? sessionId}) async {
if (isLoading == true) return -2;
isLoading = true;
notifyListeners();
late Response response;
try {
final Map<String, dynamic> body = {
"pageSize": isSearchBy ? searchPageItemNumber : pageItemNumber,
"pageNumber": isSearchBy ? (searchDevices.length / searchPageItemNumber).ceil() + 1 : devices.length ~/ pageItemNumber + 1,
"sessionId": sessionId ?? 0,
"assetSerialNo": search?.assetSerialNumber ?? '',
"assetName": search?.assetName ?? '',
"model": search?.model ?? '',
"manufacturer": search?.manufacturer ?? '',
"supplier": search?.supplier ?? '',
"siteName": search?.site ?? '',
// "buildingName":search?.??'',
// "floorName": search?.f??'',
"departmentName": search?.department ?? '',
// "roomName": search?.room
};
// if (search != null) body.addAll(search.toJson());
response = await ApiManager.instance.post(URLs.getAssetsTemp, body: body);
} catch (error) {
isLoading = false;
stateCode = -1;
notifyListeners();
return -1;
}
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List equipmentListJson = json.decode(response.body)["data"];
var dList = equipmentListJson.map<AssetInventoryModel>((asset) => AssetInventoryModel.fromJson(asset)).toList() ?? [];
isSearchBy ? _searchDevices.addAll(dList) : _devices.addAll(dList);
nextPage = true;
} else {
nextPage = false;
}
isLoading = false;
notifyListeners();
return response.statusCode;
}
Future<bool> markAsComplete({
required Map<String, dynamic> payload,
}) async {
isLoading = true;
try {
final response = await ApiManager.instance.post(URLs.convertDetailToComplete, body: payload);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
isLoading = false;
notifyListeners();
return true;
} else {
isLoading = false;
notifyListeners();
return false;
}
} catch (error) {
isLoading = false;
notifyListeners();
return false;
}
}
}

@ -30,8 +30,7 @@ class RequestItemViewList extends StatelessWidget {
if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading);
switch (list[index].transactionType) {
case 1:
// return ServiceRequestItemView(requestDetails: list[index]);
return InventorySessionCard(requestDetails: list[index]);
return ServiceRequestItemView(requestDetails: list[index]);
case 2:
return GasRefillItemView(requestDetails: list[index]);
case 3:

@ -26,6 +26,7 @@ class AssetPicker extends StatelessWidget {
Color? backgroundColor;
final bool forPPM;
final bool showLoading;
final bool enablePickManually;
final bool multiSelection;
AssetPicker(
@ -45,7 +46,7 @@ class AssetPicker extends StatelessWidget {
this.showAssetInfo = true,
this.showBorder = false,
this.multiSelection = false,
this.forPPM = false,
this.forPPM = false, this.enablePickManually = true,
this.showLoading = false})
: assert(
multiSelection == false || onMultiAssetPick != null,
@ -83,6 +84,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr(
title: context.translation.assetScan,
multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as List<Asset>?;
if (device?.isNotEmpty ?? false) {
onMultiAssetPick!(device!);
@ -92,6 +94,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr(
title: context.translation.assetScan,
multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as Asset?;
if (device != null) {
onPick!(device);
@ -121,6 +124,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr(
title: context.translation.assetScan,
multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as List<Asset>?;
if (device?.isNotEmpty ?? false) {
onMultiAssetPick!(device!);
@ -130,6 +134,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr(
title: context.translation.assetScan,
multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as Asset?;
if (device != null) {
onPick!(device);
@ -140,7 +145,7 @@ class AssetPicker extends StatelessWidget {
if (deviceList.isNotEmpty && showAssetInfo)
ListView.separated(
shrinkWrap: true,
padding: EdgeInsets.only(top: 16),
padding: const EdgeInsets.only(top: 16),
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (cxt, index) => _assetInfoView(deviceList[index], context),
separatorBuilder: (cxt, index) => 12.height,
@ -204,10 +209,10 @@ class AssetPicker extends StatelessWidget {
],
),
8.height,
"${context.translation.assetNo}: ${device!.assetNumber}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
"${context.translation.assetNo}: ${device.assetNumber}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
2.height,
// "${context.translation.manufacture}: ${device.modelDefinition?.manufacturerName}".bodyText(context),
"${context.translation.model}: ${device!.modelDefinition?.modelName}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
"${context.translation.model}: ${device.modelDefinition?.modelName}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
// "${context.translation.serialNumber}: ${device.assetNumber}".bodyText(context),
// const Divider().defaultStyle(context),
// "${context.translation.department}: ${device.department?.departmentName}".bodyText(context),

@ -20,9 +20,10 @@ import '../../pages/device_transfer/search_device_page.dart';
class AssetScanQr extends StatefulWidget {
static const String id = "/asset-scan-qr";
const AssetScanQr({Key? key, required this.title, this.multiSelection = false}) : super(key: key);
const AssetScanQr({Key? key, required this.title, this.multiSelection = false,this.enablePickManually = true}) : super(key: key);
final String title;
final bool multiSelection;
final bool enablePickManually;
@override
_AssetScanQrState createState() => _AssetScanQrState();
@ -86,6 +87,13 @@ class _AssetScanQrState extends State<AssetScanQr> {
controller.scannedDataStream.listen((scanData) async {
if (!_scanDone) {
_scanDone = true;
if(!widget.enablePickManually){
if(scanData.code!=null){
Navigator.of(context).pop(Asset(assetNumber: scanData.code!));
}else{
_scanDone = false;
}
}else{
final result = await _getDevice(scanData.code!, isQr: true);
if (result.isNotEmpty) {
if (widget.multiSelection) {
@ -97,6 +105,7 @@ class _AssetScanQrState extends State<AssetScanQr> {
_scanDone = false;
}
}
}
});
},
),
@ -109,6 +118,7 @@ class _AssetScanQrState extends State<AssetScanQr> {
),
],
).expanded,
if(widget.enablePickManually)
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(

Loading…
Cancel
Save