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