You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cloudsolutions-atoms/lib/modules/copilot/copilot_helper.dart

194 lines
7.3 KiB
Dart

import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:permission_handler/permission_handler.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/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/predict_device_model.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/views/widgets/equipment/predict_device_list.dart';
enum _ImagePickSource { camera, gallery, files }
class CopilotHelper {
static Future<PredictedAsset?> pickImageFromCamera(BuildContext context, {bool pickMode = false}) {
return _pickImage(context, pickMode: pickMode, allowGallery: false);
}
static Future<PredictedAsset?> pickImageForInventorySession(BuildContext context, {bool pickMode = true}) {
return _pickImage(context, pickMode: pickMode, allowGallery: true);
}
static Future<PredictedAsset?> _pickImage(BuildContext context, {bool pickMode = false, bool allowGallery = false}) async {
_ImagePickSource source = _ImagePickSource.camera;
if (allowGallery) {
final _ImagePickSource? selected = await _showImageSourceSheet(context);
if (selected == null) return null;
if (!context.mounted) return null;
source = selected;
}
if (source == _ImagePickSource.files) {
return _pickFromFiles(context, pickMode: pickMode);
}
if (source == _ImagePickSource.gallery) {
return openCamera(context, pickMode: pickMode, source: ImageSource.gallery);
}
final status = await Permission.camera.status;
if (status.isGranted) {
return openCamera(context, pickMode: pickMode, source: ImageSource.camera);
}
final permission = await Permission.camera.request();
if (permission.isGranted) {
return openCamera(context, pickMode: pickMode, source: ImageSource.camera);
}
if (permission.isPermanentlyDenied) {
await openAppSettings();
return null;
}
debugPrint('Camera permission denied');
return null;
}
static Future<PredictedAsset?> _pickFromFiles(BuildContext context, {bool pickMode = false}) async {
final FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.image,
allowMultiple: false,
);
final String? path = result?.files.single.path;
if (path == null) return null;
final File imageFile = File(path);
debugPrint('CopilotHelper: picked image extension = ${imageFile.path.split('.').last}');
if (!context.mounted) return null;
return uploadImage(imageFile, context, pickMode: pickMode);
}
static Future<_ImagePickSource?> _showImageSourceSheet(BuildContext context) {
return showModalBottomSheet<_ImagePickSource>(
context: context,
builder: (BuildContext context) {
Widget sourceCard({required String icon, required String label, required VoidCallback onTap}) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColor.background(context),
borderRadius: BorderRadius.circular(16),
border: Border.all(color: AppColor.borderColor(context), width: 2),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
icon.toSvgAsset(width: 24, height: 24, color: AppColor.icon2Color(context)),
label.bodyText2(context).custom(color: AppColor.labelTextStyleColor(context)),
],
),
).onPress(onTap);
}
List<Widget> listItems = [
sourceCard(
icon: 'camera_icon',
label: '${context.translation.open}\n${context.translation.camera}',
onTap: () => Navigator.of(context).pop(_ImagePickSource.camera),
),
sourceCard(
icon: 'gallery_icon',
label: '${context.translation.open}\n${context.translation.gallery}',
onTap: () => Navigator.of(context).pop(_ImagePickSource.gallery),
),
sourceCard(
icon: 'file_icon',
label: '${context.translation.open}\n${context.translation.files}',
onTap: () => Navigator.of(context).pop(_ImagePickSource.files),
),
];
return SafeArea(
top: false,
child: Container(
width: double.infinity,
color: AppColor.bottomSheetColor(context),
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'Scan Asset'.addTranslation.heading4(context),
GridView.builder(
padding: const EdgeInsets.only(top: 16, bottom: 0),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 16, mainAxisSpacing: 16),
itemCount: listItems.length,
itemBuilder: (context, index) => listItems[index],
),
],
),
),
);
},
);
}
static Future<PredictedAsset?> openCamera(BuildContext context, {bool pickMode = false, ImageSource source = ImageSource.camera}) async {
final XFile? pickedFile = await ImagePicker().pickImage(
source: source,
imageQuality: 70,
);
if (pickedFile == null) {
return null;
}
final File imageFile = File(pickedFile.path);
debugPrint('CopilotHelper: picked image extension = ${imageFile.path.split('.').last}');
if (!context.mounted) return null;
return uploadImage(imageFile, context, pickMode: pickMode);
}
static Future<PredictedAsset?> uploadImage(File imageFile, BuildContext context, {bool pickMode = false}) async {
try {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
AssetProvider assetProvider = Provider.of<AssetProvider>(context, listen: false);
PredictDeviceResponse? response = await assetProvider.predictDevice(imageFile);
Navigator.pop(context);
if (response != null && response.success == true) {
final List<PredictedAsset> predictedAssetList = response.predictedAsset ?? [];
if (predictedAssetList.isNotEmpty) {
return Navigator.push<PredictedAsset?>(
context,
MaterialPageRoute(builder: (context) => PredictDeviceView(predictedAsset: predictedAssetList, pickMode: pickMode)),
);
} else {
context.showInfoDialog("No Predicted asset found");
}
} else {
context.showInfoDialog("Failed to recognize the asset. Please try again.");
}
} catch (e) {
debugPrint('Upload error: $e');
}
return null;
}
}