device predication inprogess
parent
8cc76265b1
commit
2ae26cc363
@ -0,0 +1,116 @@
|
|||||||
|
class PredictDeviceResponse {
|
||||||
|
bool? success;
|
||||||
|
String? timestamp;
|
||||||
|
List<PredictedAsset>? predictedAsset;
|
||||||
|
|
||||||
|
PredictDeviceResponse({
|
||||||
|
this.success,
|
||||||
|
this.timestamp,
|
||||||
|
this.predictedAsset,
|
||||||
|
});
|
||||||
|
|
||||||
|
PredictDeviceResponse.fromJson(Map<String, dynamic> json) {
|
||||||
|
success = json['success'];
|
||||||
|
timestamp = json['timestamp'];
|
||||||
|
|
||||||
|
if (json['PredictedAsset'] != null) {
|
||||||
|
predictedAsset = <PredictedAsset>[];
|
||||||
|
|
||||||
|
for (var item in json['PredictedAsset']) {
|
||||||
|
predictedAsset!.add(
|
||||||
|
PredictedAsset.fromJson(item),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'success': success,
|
||||||
|
'timestamp': timestamp,
|
||||||
|
'PredictedAsset':
|
||||||
|
predictedAsset?.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PredictedAsset {
|
||||||
|
String? assetId;
|
||||||
|
String? assetName;
|
||||||
|
num? confidence;
|
||||||
|
String? confidencePercent;
|
||||||
|
PredictedAssetMetadata? metadata;
|
||||||
|
|
||||||
|
PredictedAsset({
|
||||||
|
this.assetId,
|
||||||
|
this.assetName,
|
||||||
|
this.confidence,
|
||||||
|
this.confidencePercent,
|
||||||
|
this.metadata,
|
||||||
|
});
|
||||||
|
|
||||||
|
PredictedAsset.fromJson(Map<String, dynamic> json) {
|
||||||
|
assetId = json['assetid'];
|
||||||
|
assetName = json['asset_name'];
|
||||||
|
confidence = json['confidence'];
|
||||||
|
confidencePercent = json['confidence_percent'];
|
||||||
|
|
||||||
|
if (json['metadata'] != null) {
|
||||||
|
metadata = PredictedAssetMetadata.fromJson(
|
||||||
|
json['metadata'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'assetid': assetId,
|
||||||
|
'asset_name': assetName,
|
||||||
|
'confidence': confidence,
|
||||||
|
'confidence_percent': confidencePercent,
|
||||||
|
'metadata': metadata?.toJson(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PredictedAssetMetadata {
|
||||||
|
String? siteId;
|
||||||
|
String? siteName;
|
||||||
|
String? assetName;
|
||||||
|
String? oracleCode;
|
||||||
|
String? assetNumber;
|
||||||
|
String? departmentId;
|
||||||
|
String? departmentName;
|
||||||
|
|
||||||
|
PredictedAssetMetadata({
|
||||||
|
this.siteId,
|
||||||
|
this.siteName,
|
||||||
|
this.assetName,
|
||||||
|
this.oracleCode,
|
||||||
|
this.assetNumber,
|
||||||
|
this.departmentId,
|
||||||
|
this.departmentName,
|
||||||
|
});
|
||||||
|
|
||||||
|
PredictedAssetMetadata.fromJson(Map<String, dynamic> json) {
|
||||||
|
siteId = json['site_id'];
|
||||||
|
siteName = json['site_name'];
|
||||||
|
assetName = json['asset_name'];
|
||||||
|
oracleCode = json['oracle_code'];
|
||||||
|
assetNumber = json['asset_number'];
|
||||||
|
departmentId = json['department_id'];
|
||||||
|
departmentName = json['department_name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'site_id': siteId,
|
||||||
|
'site_name': siteName,
|
||||||
|
'asset_name': assetName,
|
||||||
|
'oracle_code': oracleCode,
|
||||||
|
'asset_number': assetNumber,
|
||||||
|
'department_id': departmentId,
|
||||||
|
'department_name': departmentName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:test_sa/extensions/context_extension.dart';
|
||||||
|
import 'package:test_sa/extensions/int_extensions.dart';
|
||||||
|
import 'package:test_sa/extensions/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/views/widgets/item_views/info_text_widget.dart';
|
||||||
|
|
||||||
|
import '../../../new_views/app_style/app_color.dart';
|
||||||
|
|
||||||
|
class PredictDeviceItemGridView extends StatelessWidget {
|
||||||
|
final PredictedAsset device;
|
||||||
|
final Function(PredictedAsset) onPressed;
|
||||||
|
|
||||||
|
const PredictDeviceItemGridView({Key? key, required this.device, required this.onPressed}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
device.assetName!.cleanupWhitespace.capitalizeFirstOfEach,
|
||||||
|
maxLines: 2,
|
||||||
|
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)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).expanded.onPress(() => onPressed(device)).toShadowContainer(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:test_sa/extensions/context_extension.dart';
|
||||||
|
import 'package:test_sa/extensions/int_extensions.dart';
|
||||||
|
import 'package:test_sa/extensions/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/new_views/app_style/app_color.dart';
|
||||||
|
import 'package:test_sa/views/widgets/item_views/info_header_widget.dart';
|
||||||
|
import 'package:test_sa/views/widgets/item_views/info_text_widget.dart';
|
||||||
|
|
||||||
|
class PredictDeviceItemView extends StatelessWidget {
|
||||||
|
final PredictedAsset device;
|
||||||
|
final Function(PredictedAsset) onPressed;
|
||||||
|
final Widget? selectButton;
|
||||||
|
final bool isSelected;
|
||||||
|
|
||||||
|
const PredictDeviceItemView({Key? key, required this.device, required this.onPressed, this.selectButton, this.isSelected = false}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
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)
|
||||||
|
],
|
||||||
|
))
|
||||||
|
],
|
||||||
|
).expanded.toShadowContainer(context, borderColor: isSelected ? AppColor.primary10 : Colors.transparent).onPress(() => onPressed(device));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,180 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:test_sa/controllers/providers/api/devices_provider.dart';
|
||||||
|
import 'package:test_sa/extensions/context_extension.dart';
|
||||||
|
import 'package:test_sa/extensions/int_extensions.dart';
|
||||||
|
import 'package:test_sa/extensions/widget_extensions.dart';
|
||||||
|
import 'package:test_sa/models/device/predict_device_model.dart';
|
||||||
|
import 'package:test_sa/new_views/app_style/app_color.dart';
|
||||||
|
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
|
||||||
|
import 'package:test_sa/views/widgets/equipment/asset_detail_page.dart';
|
||||||
|
import 'package:test_sa/views/widgets/equipment/predict_device_item_grid_view.dart';
|
||||||
|
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";
|
||||||
|
List<PredictedAsset> predictedAsset;
|
||||||
|
|
||||||
|
PredictDeviceView({Key? key, required this.predictedAsset}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_PredictDeviceViewState createState() => _PredictDeviceViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PredictDeviceViewState extends State<PredictDeviceView> with SingleTickerProviderStateMixin {
|
||||||
|
late AssetProvider _devicesProvider;
|
||||||
|
bool showListView = true;
|
||||||
|
late AnimationController _animationController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_animationController = AnimationController(
|
||||||
|
duration: const Duration(milliseconds: 1200),
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
|
_animationController.forward();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_animationController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
_devicesProvider = Provider.of<AssetProvider>(context);
|
||||||
|
return Scaffold(
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
|
appBar: DefaultAppBar(
|
||||||
|
title: 'Predicated Devices',
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(!showListView ? Icons.view_list_sharp : Icons.grid_view_outlined, color: AppColor.icon2Color(context)),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
iconSize: 20,
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
tooltip: !showListView ? "View as List" : "View as Grid",
|
||||||
|
onPressed: () => setState(() {
|
||||||
|
showListView = !showListView;
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
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<double>(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<Offset>(
|
||||||
|
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<double>(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<Offset>(
|
||||||
|
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)),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue