last63

Untitled

Mar 19th, 2025
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.93 KB | None | 0 0
  1. import 'dart:io';
  2.  
  3. import 'package:firebase_test/ui/ui/attedance/attendance/attendance_page.dart';
  4. import 'package:firebase_test/utils/facedection/google_ml_kit.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
  7. import 'package:image_picker/image_picker.dart';
  8. import 'package:lottie/lottie.dart';
  9. import 'package:geolocator/geolocator.dart';
  10. import 'package:camera/camera.dart';
  11. import 'package:permission_handler/permission_handler.dart'; // Import the permission_handler package
  12.  
  13. class CameraPage extends StatefulWidget {
  14. const CameraPage({super.key});
  15.  
  16. @override
  17. State<CameraPage> createState() => _CameraPageState();
  18. }
  19.  
  20. class _CameraPageState extends State<CameraPage> with TickerProviderStateMixin {
  21. //set face detection
  22. FaceDetector faceDetector = GoogleMLKit.vision.faceDetector(FaceDetectorOptions(
  23. enableContours: true,
  24. enableClassification: true,
  25. enableTracking: true,
  26. enableLandmarks: true
  27. ));
  28.  
  29. List<CameraDescription>? cameras;
  30. CameraController? controller;
  31. XFile? image;
  32. bool isBusy = false;
  33.  
  34. @override
  35. void initState() {
  36. loadCamera();
  37. super.initState();
  38. }
  39.  
  40. loadCamera() async {
  41. // Request camera permission
  42. var status = await Permission.camera.status;
  43. if (status.isDenied) {
  44. await Permission.camera.request(); // Request the permission
  45. status = await Permission.camera.status; //check the status after request
  46. }
  47.  
  48. if (status.isGranted) {
  49. cameras = await availableCameras();
  50. if (cameras != null) {
  51. // Use the first available camera (usually the back camera)
  52. controller = CameraController(cameras![0], ResolutionPreset.max);
  53. try{
  54. await controller!.initialize(); // Initialize the camera.
  55. if (mounted) {
  56. setState(() {});
  57. }
  58. } on CameraException catch (e){
  59. print('Error initializing camera: $e');
  60. _showCameraErrorSnackBar("Error initializing camera: ${e.description}");
  61. return;
  62.  
  63. }
  64.  
  65. } else {
  66. _showCameraErrorSnackBar("No cameras found!");
  67. }
  68. } else {
  69. _showCameraErrorSnackBar("Camera permission not granted");
  70. }
  71. }
  72.  
  73. //show snackbar
  74. void _showCameraErrorSnackBar(String message) {
  75. if (mounted) {
  76. ScaffoldMessenger.of(context).showSnackBar(SnackBar(
  77. content: Row(
  78. children: [
  79. const Icon(
  80. Icons.camera_enhance_outlined,
  81. color: Colors.white,
  82. ),
  83. const SizedBox(width: 10),
  84. Text(message, style: const TextStyle(color: Colors.white)),
  85. ],
  86. ),
  87. backgroundColor: Colors.blueGrey,
  88. shape: const StadiumBorder(),
  89. behavior: SnackBarBehavior.floating,
  90. ));
  91. }
  92. }
  93.  
  94. @override
  95. void dispose() {
  96. controller?.dispose();
  97. faceDetector.close(); // Dispose the face detector
  98. super.dispose();
  99. }
  100.  
  101. @override
  102. Widget build(BuildContext context) {
  103. Size size = MediaQuery.of(context).size;
  104.  
  105. //set loading
  106. showLoaderDialog(BuildContext context) {
  107. AlertDialog alert = AlertDialog(
  108. content: Row(
  109. children: [
  110. const CircularProgressIndicator(valueColor:
  111. AlwaysStoppedAnimation<Color>(Colors.blueAccent)),
  112. Container(
  113. margin: const EdgeInsets.only(left: 20),
  114. child: const Text("Checking the data...")
  115. ),
  116. ],
  117. ),
  118. );
  119. showDialog(
  120. barrierDismissible: false,
  121. context: context,
  122. builder: (BuildContext context) {
  123. return alert;
  124. },
  125. );
  126. }
  127. return Scaffold(
  128. appBar: AppBar(
  129. elevation: 0,
  130. backgroundColor: Colors.blueAccent,
  131. leading: IconButton(
  132. icon: const Icon(Icons.arrow_back_ios, color: Colors.white),
  133. onPressed: () => Navigator.of(context).pop(),
  134. ),
  135. title: const Text(
  136. "Capture a selfie image",
  137. style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white),
  138. ),
  139. ),
  140. body: Stack(
  141. children: [
  142. SizedBox(
  143. height: size.height,
  144. width: size.width,
  145. child: controller == null
  146. ? const Center(child: Text("Ups, camera error!",
  147. style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)))
  148. : !controller!.value.isInitialized
  149. ? const Center(child: CircularProgressIndicator())
  150. : CameraPreview(controller!)
  151. ),
  152. Padding(
  153. padding: const EdgeInsets.only(top: 40),
  154. child: Lottie.asset(
  155. "assets/raw/face_id_ring.json",
  156. fit: BoxFit.cover,
  157. ),
  158. ),
  159. Align(
  160. alignment: Alignment.bottomCenter,
  161. child: Container(
  162. width: size.width,
  163. height: 200,
  164. padding: const EdgeInsets.symmetric(horizontal: 30),
  165. decoration: const BoxDecoration(
  166. color: Colors.white,
  167. borderRadius: BorderRadius.only(
  168. topLeft: Radius.circular(28),
  169. topRight: Radius.circular(28),
  170. ),
  171. ),
  172. child: Column(
  173. children: [
  174. const SizedBox(
  175. height: 20,
  176. ),
  177. const Text(
  178. "Make sure you're in a well-lit area so your face is clearly visible.",
  179. style: TextStyle(fontSize: 16, color: Colors.black),
  180. ),
  181. Padding(
  182. padding: const EdgeInsets.only(top: 40),
  183. child: ClipOval(
  184. child: Material(
  185. color: Colors.blueAccent, // Button color
  186. child: InkWell(
  187. splashColor: Colors.blue, // Splash color
  188. onTap: () async {
  189. final hasPermission = await handleLocationPermission();
  190. try {
  191. if (controller != null && controller!.value.isInitialized) {
  192. controller!.setFlashMode(FlashMode.off);
  193. image = await controller!.takePicture();
  194. setState(() {
  195. if (hasPermission) {
  196. showLoaderDialog(context);
  197. final inputImage = InputImage.fromFilePath(image!.path);
  198. processImage(inputImage); // Await here
  199. }
  200. else {
  201. ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
  202. content: Row(
  203. children: [
  204. Icon(
  205. Icons.location_on_outlined,
  206. color: Colors.white,
  207. ),
  208. SizedBox(width: 10),
  209. Text("Please allow the permission first!",
  210. style: TextStyle(color: Colors.white),
  211. )
  212. ],
  213. ),
  214. backgroundColor: Colors.blueGrey,
  215. shape: StadiumBorder(),
  216. behavior: SnackBarBehavior.floating,
  217. ));
  218. }
  219. });
  220. }
  221. } catch (e) {
  222. if (mounted) {
  223. ScaffoldMessenger.of(context).showSnackBar(SnackBar(
  224. content: Row(
  225. children: [
  226. const Icon(
  227. Icons.error_outline,
  228. color: Colors.white,
  229. ),
  230. const SizedBox(width: 10),
  231. Text("Ups, $e",
  232. style: const TextStyle(color: Colors.white),
  233. )
  234. ],
  235. ),
  236. backgroundColor: Colors.blueGrey,
  237. shape: const StadiumBorder(),
  238. behavior: SnackBarBehavior.floating,
  239. ));
  240. }
  241. }
  242. },
  243. child: const SizedBox(
  244. width: 56,
  245. height: 56,
  246. child: Icon(
  247. Icons.camera_enhance_outlined,
  248. color: Colors.white,
  249. ),
  250. ),
  251. ),
  252. ),
  253. ),
  254. ),
  255. ],
  256. ),
  257. ),
  258. ),
  259. ],
  260. ),
  261. );
  262. }
  263.  
  264. //permission location
  265. Future<bool> handleLocationPermission() async {
  266. bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
  267. if (!serviceEnabled) {
  268. if(mounted){
  269. ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
  270. content: Row(
  271. children: [
  272. Icon(
  273. Icons.location_off,
  274. color: Colors.white,
  275. ),
  276. SizedBox(width: 10),
  277. Text("Location services are disabled. Please enable the services.",
  278. style: TextStyle(color: Colors.white),
  279. )
  280. ],
  281. ),
  282. backgroundColor: Colors.blueGrey,
  283. shape: StadiumBorder(),
  284. behavior: SnackBarBehavior.floating,
  285. ));
  286. }
  287. return false;
  288. }
  289.  
  290. LocationPermission permission = await Geolocator.checkPermission();
  291. if (permission == LocationPermission.denied) {
  292. permission = await Geolocator.requestPermission();
  293. if (permission == LocationPermission.denied) {
  294. if(mounted){
  295. ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
  296. content: Row(
  297. children: [
  298. Icon(
  299. Icons.location_off,
  300. color: Colors.white,
  301. ),
  302. SizedBox(width: 10),
  303. Text("Location permission denied.",
  304. style: TextStyle(color: Colors.white),
  305. )
  306. ],
  307. ),
  308. backgroundColor: Colors.blueGrey,
  309. shape: StadiumBorder(),
  310. behavior: SnackBarBehavior.floating,
  311. ));
  312. }
  313. return false;
  314. }
  315. }
  316.  
  317. if (permission == LocationPermission.deniedForever) {
  318. if(mounted){
  319. ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
  320. content: Row(
  321. children: [
  322. Icon(
  323. Icons.location_off,
  324. color: Colors.white,
  325. ),
  326. SizedBox(width: 10),
  327. Text("Location permission denied forever, we cannot access.",
  328. style: TextStyle(color: Colors.white),
  329. )
  330. ],
  331. ),
  332. backgroundColor: Colors.blueGrey,
  333. shape: StadiumBorder(),
  334. behavior: SnackBarBehavior.floating,
  335. ));
  336. }
  337. return false;
  338. }
  339. return true;
  340. }
  341.  
  342. //face detection
  343. Future<void> processImage(InputImage inputImage) async {
  344. if (isBusy) return;
  345. isBusy = true;
  346. try {
  347. final faces = await faceDetector.processImage(inputImage);
  348. isBusy = false;
  349.  
  350. if (mounted) {
  351. Navigator.of(context).pop(true); // Dismiss dialog first
  352. if (faces.isNotEmpty) {
  353. Navigator.pushReplacement(context,
  354. MaterialPageRoute(builder: (context) => AttendancePage(image: image)));
  355. } else {
  356. ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
  357. content: Row(
  358. children: [
  359. Icon(
  360. Icons.face_retouching_natural_outlined,
  361. color: Colors.white,
  362. ),
  363. SizedBox(width: 10),
  364. Expanded(
  365. child: Text(
  366. "Ups, make sure that your face is clearly visible!",
  367. style: TextStyle(color: Colors.white),
  368. ),
  369. )
  370. ],
  371. ),
  372. backgroundColor: Colors.blueGrey,
  373. shape: StadiumBorder(),
  374. behavior: SnackBarBehavior.floating,
  375. ));
  376. }
  377. }
  378. } catch (e) {
  379. isBusy = false; // Ensure isBusy is set to false on error
  380. if (mounted) {
  381. ScaffoldMessenger.of(context).showSnackBar(SnackBar(
  382. content: Row(
  383. children: [
  384. const Icon(Icons.error, color: Colors.white),
  385. const SizedBox(width: 8),
  386. Text('Error processing image: $e', style: const TextStyle(color: Colors.white)),
  387. ],
  388. ),
  389. backgroundColor: Colors.red,
  390. duration: const Duration(seconds: 5),
  391. ));
  392. }
  393. print("Error processing image: $e"); // Log the error
  394. }
  395. }
  396. }
  397.  
  398.  
Advertisement
Add Comment
Please, Sign In to add comment