feat: integrate camera package and update related dependencies in pubspec.lock for enhanced image handling capabilities
This commit is contained in:
@@ -14,6 +14,8 @@ Future<void> setupAllCoreProvider() async {
|
||||
// await FMTCObjectBoxBackend().initialise();
|
||||
|
||||
await diCore.allReady();
|
||||
|
||||
|
||||
}
|
||||
|
||||
Future<void> _setupLocalStorage() async {
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import 'package:camera/camera.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:rasadyar_core/utils/logger_utils.dart';
|
||||
|
||||
class RImagePickerController extends ChangeNotifier {
|
||||
List<CameraDescription> _cameras = [];
|
||||
|
||||
CameraController? cameraController;
|
||||
|
||||
bool isLoading = false;
|
||||
bool isCameraReady = false;
|
||||
|
||||
List<XFile> capturedImages = <XFile>[];
|
||||
|
||||
Future<void> getAvailableCameras() async {
|
||||
_cameras = await availableCameras();
|
||||
}
|
||||
|
||||
Future<void> openCamera() async {
|
||||
try {
|
||||
isLoading = true;
|
||||
await disposeCameraController();
|
||||
await getAvailableCameras();
|
||||
if (_cameras.isNotEmpty) {
|
||||
cameraController = CameraController(
|
||||
_cameras[0],
|
||||
ResolutionPreset.high,
|
||||
enableAudio: false,
|
||||
);
|
||||
await cameraController?.initialize();
|
||||
notifyListeners();
|
||||
isCameraReady = true;
|
||||
isLoading = false;
|
||||
} else {
|
||||
isCameraReady = false;
|
||||
isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
} catch (e) {
|
||||
isCameraReady = false;
|
||||
isLoading = false;
|
||||
notifyListeners();
|
||||
eLog(e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> takePicture() async {
|
||||
if (cameraController == null || !cameraController!.value.isInitialized)
|
||||
return;
|
||||
if (isLoading) return;
|
||||
|
||||
try {
|
||||
isLoading = true;
|
||||
notifyListeners();
|
||||
final image = await cameraController!.takePicture();
|
||||
|
||||
capturedImages.add(image);
|
||||
|
||||
isLoading = false;
|
||||
} catch (e) {
|
||||
eLog(e);
|
||||
} finally {
|
||||
isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void removeImage(int index) {
|
||||
if (index < capturedImages.length) {
|
||||
capturedImages.removeAt(index);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> disposeCameraController() async {
|
||||
await cameraController?.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:camera/camera.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
class RImagePicker extends StatefulWidget {
|
||||
const RImagePicker({super.key, this.maxImages, required this.controller});
|
||||
final int? maxImages;
|
||||
final RImagePickerController controller;
|
||||
|
||||
@override
|
||||
State<RImagePicker> createState() => _RImagePickerState();
|
||||
}
|
||||
|
||||
class _RImagePickerState extends State<RImagePicker> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
widget.controller.openCamera();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
widget.controller.disposeCameraController();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
body: AnimatedBuilder(
|
||||
animation: widget.controller,
|
||||
builder: (context, child) {
|
||||
if (!widget.controller.isCameraReady) {
|
||||
return const Center(
|
||||
child: CoreLoadingIndicator(
|
||||
color: Colors.white,
|
||||
variant: CoreLoadingVariant.cupertino,
|
||||
size: CoreLoadingSize.medium,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
CameraPreview(widget.controller.cameraController!),
|
||||
|
||||
Positioned(
|
||||
bottom: 40,
|
||||
right: 10,
|
||||
|
||||
child: RFab(
|
||||
onPressed: () => Get.back(),
|
||||
icon: Assets.vec.checkSvg.svg(),
|
||||
backgroundColor: AppColor.greenNormal,
|
||||
),
|
||||
),
|
||||
|
||||
if (widget.maxImages == null ||
|
||||
widget.controller.capturedImages.length <
|
||||
(widget.maxImages ?? 1000)) ...[
|
||||
Positioned(
|
||||
bottom: 40,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Center(
|
||||
child: FloatingActionButton(
|
||||
onPressed: widget.controller.isLoading
|
||||
? null
|
||||
: () async {
|
||||
await widget.controller.takePicture();
|
||||
},
|
||||
backgroundColor: Colors.white,
|
||||
child: widget.controller.isLoading
|
||||
? const SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
Colors.black,
|
||||
),
|
||||
),
|
||||
)
|
||||
: const Icon(Icons.camera_alt, color: Colors.black),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
if (widget.controller.capturedImages.isNotEmpty) ...[
|
||||
Positioned(
|
||||
bottom: 120,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: 100.h,
|
||||
child: ListView.separated(
|
||||
itemCount: widget.controller.capturedImages.length,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20.w,
|
||||
vertical: 10.h,
|
||||
),
|
||||
scrollDirection: Axis.horizontal,
|
||||
separatorBuilder: (context, index) => SizedBox(width: 10.w),
|
||||
itemBuilder: (context, index) {
|
||||
final image = widget.controller.capturedImages[index];
|
||||
return Container(
|
||||
width: 100.w,
|
||||
height: 100.h,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white, width: 2),
|
||||
borderRadius: BorderRadius.circular(8.r),
|
||||
image: DecorationImage(
|
||||
image: FileImage(File(image.path)),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
Positioned(
|
||||
top: 2,
|
||||
right: 2,
|
||||
child: GestureDetector(
|
||||
onTap: () =>
|
||||
widget.controller.removeImage(index),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(4),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.red,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -50,3 +50,7 @@ export 'tabs/new_tab.dart';
|
||||
export 'tabs/r_segment.dart';
|
||||
export 'tabs/tab.dart';
|
||||
export 'vec_widget.dart';
|
||||
|
||||
//image picker
|
||||
export 'image_picker/image_picker_controller.dart';
|
||||
export 'image_picker/image_picker_widget.dart';
|
||||
|
||||
Reference in New Issue
Block a user