From 2121cd7d9d64e00d897a0ef9bae558829fe8c642 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 <50428976+WaseemAbbasi22@users.noreply.github.com> Date: Mon, 14 Sep 2026 11:34:28 +0300 Subject: [PATCH] device predication implemented --- .../providers/api/devices_provider.dart | 22 +- lib/models/device/predict_device_model.dart | 6 +- .../widgets/equipment/my_assets_page.dart | 18 +- .../predict_device_item_grid_view.dart | 31 +-- .../equipment/predict_device_item_view.dart | 36 +-- .../equipment/predict_device_list.dart | 214 +++++++++--------- 6 files changed, 149 insertions(+), 178 deletions(-) diff --git a/lib/controllers/providers/api/devices_provider.dart b/lib/controllers/providers/api/devices_provider.dart index 55db8d07..77b75e5f 100644 --- a/lib/controllers/providers/api/devices_provider.dart +++ b/lib/controllers/providers/api/devices_provider.dart @@ -10,6 +10,7 @@ import 'package:test_sa/controllers/api_routes/http_status_manger.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/models/device/asset_by_id_model.dart'; import 'package:test_sa/models/device/asset_search.dart'; +import 'package:test_sa/models/device/predict_device_model.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/user.dart'; @@ -259,31 +260,30 @@ class AssetProvider extends ChangeNotifier { } } - Future predictDevice(File imageFile) async { - late Response response; - + Future predictDevice(File image) async { try { final files = >[ MultipartFile.fromPath( 'file', - imageFile.path, + image.path, ), ]; - log('Uploading file: ${files.first.runtimeType}'); - response = await ApiManager.instance.multiPart( + + final response = await ApiManager.instance.multiPart( URLs.predictDevice, body: {}, files: files, ); if (response.statusCode >= 200 && response.statusCode < 300) { - return true; + final responseData = json.decode(response.body)['data']; + return PredictDeviceResponse.fromJson(responseData); + }else{ + return null; } - - return false; } catch (error) { - log('error: $error'); - return false; + debugPrint('error i got in predictDevice: $error'); + return null; } } } diff --git a/lib/models/device/predict_device_model.dart b/lib/models/device/predict_device_model.dart index 64d412ed..4084e800 100644 --- a/lib/models/device/predict_device_model.dart +++ b/lib/models/device/predict_device_model.dart @@ -13,10 +13,10 @@ class PredictDeviceResponse { success = json['success']; timestamp = json['timestamp']; - if (json['PredictedAsset'] != null) { + if (json['predictedAsset'] != null) { predictedAsset = []; - for (var item in json['PredictedAsset']) { + for (var item in json['predictedAsset']) { predictedAsset!.add( PredictedAsset.fromJson(item), ); @@ -28,7 +28,7 @@ class PredictDeviceResponse { return { 'success': success, 'timestamp': timestamp, - 'PredictedAsset': + 'predictedAsset': predictedAsset?.map((e) => e.toJson()).toList(), }; } diff --git a/lib/views/widgets/equipment/my_assets_page.dart b/lib/views/widgets/equipment/my_assets_page.dart index 0cf049fc..e60e87be 100644 --- a/lib/views/widgets/equipment/my_assets_page.dart +++ b/lib/views/widgets/equipment/my_assets_page.dart @@ -1,5 +1,5 @@ +import 'dart:developer'; import 'dart:io'; - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; @@ -12,13 +12,16 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/predict_device_model.dart'; import 'package:test_sa/modules/tm_module/device_transfer/device_filter_screen.dart'; import 'package:test_sa/modules/tm_module/device_transfer/device_search_screen.dart'; import 'package:test_sa/modules/export_module/pages/export_form_view.dart'; import 'package:test_sa/modules/export_module/models/export_module_type.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/views/widgets/equipment/asset_detail_page.dart'; import 'package:test_sa/views/widgets/equipment/asset_item_gridview.dart'; import 'package:test_sa/views/widgets/equipment/asset_item_listview.dart'; +import 'package:test_sa/views/widgets/equipment/predict_device_list.dart'; import 'package:test_sa/views/widgets/loaders/lazy_loading.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; @@ -685,8 +688,17 @@ class _MyAssetsPageState extends State with SingleTickerProviderSt Future _uploadImage(File imageFile) async { try { - await _devicesProvider.predictDevice(imageFile); - //PredictDeviceView + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + PredictDeviceResponse? response = await _devicesProvider.predictDevice(imageFile); + Navigator.pop(context); + if (response != null && response.success == true) { + final List predictedAssetList = response.predictedAsset ?? []; + if (predictedAssetList.isNotEmpty) { + Navigator.push(context, MaterialPageRoute(builder: (context) => PredictDeviceView(predictedAsset: predictedAssetList))); + } else { + debugPrint('No Predicted asset found in the response.'); + } + } } catch (e) { debugPrint('Upload error: $e'); } diff --git a/lib/views/widgets/equipment/predict_device_item_grid_view.dart b/lib/views/widgets/equipment/predict_device_item_grid_view.dart index 2d9982d8..08eec81a 100644 --- a/lib/views/widgets/equipment/predict_device_item_grid_view.dart +++ b/lib/views/widgets/equipment/predict_device_item_grid_view.dart @@ -17,8 +17,8 @@ class PredictDeviceItemGridView extends StatelessWidget { @override Widget build(BuildContext context) { return Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, children: [ Text( device.assetName!.cleanupWhitespace.capitalizeFirstOfEach, @@ -26,29 +26,12 @@ class PredictDeviceItemGridView extends StatelessWidget { overflow: TextOverflow.ellipsis, style: AppTextStyles.bodyText.copyWith(color: AppColor.textStyleColor(context)), ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - InfoTextWidget(label: context.translation.assetNumber, value: device.metadata?.assetNumber), - InfoTextWidget(label: 'Matching Percentage', value: device.confidencePercent), - InfoTextWidget(label: context.translation.oracleCode, value: device.metadata?.oracleCode), - InfoTextWidget(label: context.translation.site, value: device.metadata?.siteName), - InfoTextWidget(label: context.translation.department, value: device.metadata?.departmentName), - ], - ).expanded, - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'View Details', - style: AppTextStyles.bodyText2.copyWith(color: AppColor.primary10), - ), - 4.width, - const Icon(Icons.arrow_forward, color: AppColor.primary10, size: 14) - ], - ), + InfoTextWidget(label: context.translation.assetNumber, value: device.metadata?.assetNumber), + InfoTextWidget(label: 'Matching Percentage', value: device.confidencePercent), + InfoTextWidget(label: context.translation.oracleCode, value: device.metadata?.oracleCode), + InfoTextWidget(label: context.translation.site, value: device.metadata?.siteName), + InfoTextWidget(label: context.translation.department, value: device.metadata?.departmentName,showArrow: true,), ], - ).expanded.onPress(() => onPressed(device)).toShadowContainer(context); + ).onPress(() => onPressed(device)).toShadowContainer(context); } } diff --git a/lib/views/widgets/equipment/predict_device_item_view.dart b/lib/views/widgets/equipment/predict_device_item_view.dart index b8546ce5..2e74c864 100644 --- a/lib/views/widgets/equipment/predict_device_item_view.dart +++ b/lib/views/widgets/equipment/predict_device_item_view.dart @@ -22,34 +22,14 @@ class PredictDeviceItemView extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - InfoHeaderWidget(device.assetName!.cleanupWhitespace), - 4.height, - InfoTextWidget(label: context.translation.assetNumber, value: device.metadata?.assetNumber), - InfoTextWidget(label: 'Matching Percentage', value: device.confidencePercent), - InfoTextWidget(label: context.translation.oracleCode, value: device.metadata?.oracleCode), - InfoTextWidget(label: context.translation.site, value: device.metadata?.siteName), - InfoTextWidget(label: context.translation.department, value: device.metadata?.departmentName), - ], - ), - Align( - alignment: Alignment.bottomRight, - child: selectButton ?? - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - context.translation.viewDetails, - style: AppTextStyles.bodyText2.copyWith(color: AppColor.primary10), - ), - 4.width, - const Icon(Icons.arrow_forward, color: AppColor.primary10, size: 14) - ], - )) + InfoHeaderWidget(device.assetName!.cleanupWhitespace), + 4.height, + InfoTextWidget(label: context.translation.assetNumber, value: device.metadata?.assetNumber), + InfoTextWidget(label: 'Confidence Percentage', value: device.confidencePercent), + InfoTextWidget(label: context.translation.oracleCode, value: device.metadata?.oracleCode), + InfoTextWidget(label: context.translation.site, value: device.metadata?.siteName), + InfoTextWidget(label: context.translation.department, value: device.metadata?.departmentName,showArrow: true,), ], - ).expanded.toShadowContainer(context, borderColor: isSelected ? AppColor.primary10 : Colors.transparent).onPress(() => onPressed(device)); + ).toShadowContainer(context, borderColor: isSelected ? AppColor.primary10 : Colors.transparent).onPress(() => onPressed(device)); } } diff --git a/lib/views/widgets/equipment/predict_device_list.dart b/lib/views/widgets/equipment/predict_device_list.dart index dc5155cd..67a9d570 100644 --- a/lib/views/widgets/equipment/predict_device_list.dart +++ b/lib/views/widgets/equipment/predict_device_list.dart @@ -13,7 +13,7 @@ import 'package:test_sa/views/widgets/equipment/predict_device_item_view.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; class PredictDeviceView extends StatefulWidget { - static const String id = "/single-device-Picker"; + static const String id = "/predict_device_view"; List predictedAsset; PredictDeviceView({Key? key, required this.predictedAsset}) : super(key: key); @@ -63,118 +63,114 @@ class _PredictDeviceViewState extends State with SingleTicker ), ], ), - body: SafeArea( - child: Column( - children: [ - Expanded( - child: widget.predictedAsset.isEmpty - ? NoDataFound(message: context.translation.noDeviceFound).center - : Stack( - children: [ - AnimatedSwitcher( - duration: const Duration(milliseconds: 500), - child: showListView - ? ListView.separated( - key: const ValueKey('list_view'), - padding: const EdgeInsets.all(16), - itemCount: widget.predictedAsset.length, - separatorBuilder: (listContext, itemIndex) => 12.height, - itemBuilder: (listContext, itemIndex) { - // Calculate staggered animation delay - final delay = itemIndex * 0.08; - final animation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - delay.clamp(0.0, 0.7), - (delay + 0.4).clamp(0.0, 1.0), - curve: Curves.easeOut, - ), - ), - ); + body: Stack( + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 500), + child: showListView + ? ListView.separated( + key: const ValueKey('list_view'), + padding: const EdgeInsets.all(16), + itemCount: widget.predictedAsset.length, + separatorBuilder: (listContext, itemIndex) => 12.height, + itemBuilder: (listContext, itemIndex) { + // Calculate staggered animation delay + final delay = itemIndex * 0.08; + final animation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + delay.clamp(0.0, 0.7), + (delay + 0.4).clamp(0.0, 1.0), + curve: Curves.easeOut, + ), + ), + ); - final slideAnimation = Tween( - begin: const Offset(0.0, 0.15), - end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - delay.clamp(0.0, 0.7), - (delay + 0.4).clamp(0.0, 1.0), - curve: Curves.easeOutCubic, - ), - ), - ); + final slideAnimation = Tween( + begin: const Offset(0.0, 0.15), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + delay.clamp(0.0, 0.7), + (delay + 0.4).clamp(0.0, 1.0), + curve: Curves.easeOutCubic, + ), + ), + ); - return FadeTransition( - opacity: animation, - child: SlideTransition( - position: slideAnimation, - child: PredictDeviceItemView( - device: widget.predictedAsset[itemIndex], - onPressed: (device) { - Navigator.of(context).pushNamed(AssetDetailPage.id, arguments: device.assetId); - }, - ), - ), - ); - }, - ) - : GridView.builder( - key: const ValueKey('grid_view'), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 188 / 261, crossAxisSpacing: 12, mainAxisSpacing: 12), - itemCount: widget.predictedAsset.length, - padding: const EdgeInsets.all(16), - itemBuilder: (context, index) { - // Calculate staggered animation delay - final delay = index * 0.08; - final animation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - delay.clamp(0.0, 0.8), - (delay + 0.3).clamp(0.0, 1.0), - curve: Curves.easeOut, - ), - ), - ); + return FadeTransition( + opacity: animation, + child: SlideTransition( + position: slideAnimation, + child: PredictDeviceItemView( + device: widget.predictedAsset[itemIndex], + onPressed: (device) { + //We are not getting asset id in response only have serial number + // Navigator.of(context).pushNamed(AssetDetailPage.id, arguments: device.assetId); + }, + ), + ), + ); + }, + ) + : GridView.builder( + key: const ValueKey('grid_view'), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 12, + childAspectRatio: 1.5, + mainAxisSpacing: 12), + itemCount: widget.predictedAsset.length, + padding: const EdgeInsets.all(16), + itemBuilder: (context, index) { + // Calculate staggered animation delay + final delay = index * 0.08; + final animation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + delay.clamp(0.0, 0.8), + (delay + 0.3).clamp(0.0, 1.0), + curve: Curves.easeOut, + ), + ), + ); - final slideAnimation = Tween( - begin: const Offset(0.0, 0.3), - end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - delay.clamp(0.0, 0.8), - (delay + 0.3).clamp(0.0, 1.0), - curve: Curves.easeOutCubic, - ), - ), - ); + final slideAnimation = Tween( + begin: const Offset(0.0, 0.3), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + delay.clamp(0.0, 0.8), + (delay + 0.3).clamp(0.0, 1.0), + curve: Curves.easeOutCubic, + ), + ), + ); - return FadeTransition( - opacity: animation, - child: SlideTransition( - position: slideAnimation, - child: PredictDeviceItemGridView( - device: widget.predictedAsset[index], - onPressed: (device) { - Navigator.of(context).pushNamed(AssetDetailPage.id, arguments: device.assetId); - }, - ), - ), - ); - }, - ), - ), - if (_devicesProvider.isLoading) Align(alignment: Alignment.bottomCenter, child: CircularProgressIndicator().paddingOnly(top: 16, bottom: 16)), - ], - )), - ], - ), - ), + return FadeTransition( + opacity: animation, + child: SlideTransition( + position: slideAnimation, + child: PredictDeviceItemGridView( + device: widget.predictedAsset[index], + onPressed: (device) { + //We are not getting asset id in response only have serial number + // Navigator.of(context).pushNamed(AssetDetailPage.id, arguments: device.assetId); + }, + ), + ), + ); + }, + ), + ), + ], + ), ); } }