import 'dart:io'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:logging/logging.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as path; import 'package:uuid/uuid.dart'; import 'package:image/image.dart' as img; import 'package:image_cropper/image_cropper.dart' as img_cropper; class ImagesManager { static final ImagesManager instance = ImagesManager._internal(); ImagesManager._internal(); static final Logger log = Logger("ImagesManager"); static Uri? _imagesDirectory; Future get imageDirectory async { if (_imagesDirectory != null) return _imagesDirectory!; await _initImagesDirectory(); return _imagesDirectory!; } Future _initImagesDirectory() async { final directoryLoc = await getApplicationDocumentsDirectory(); final directoryName = "images"; final directoryPath = path.join(directoryLoc.path, directoryName); final directoryUri = Uri.directory(directoryPath); final directory = Directory.fromUri(directoryUri); if (!await directory.exists()) { log.info("Image directory does not yet exist. Creating it."); } await directory.create(recursive: true); log.info("Image directory set up at '$directory'"); _imagesDirectory = directoryUri; } Future createImage(ImageSource source) async { final XFile? ximage = await ImagePicker().pickImage(source: source); if (ximage == null) return null; final uuid = Uuid().v6(); final imageDir = await imageDirectory; final finalPath = path.join( imageDir.path, uuid + path.extension(ximage.name), ); final tempPath = path.join( imageDir.path, "${uuid}_tocrop${path.extension(ximage.name)}", ); await ximage.saveTo(tempPath); img_cropper.CroppedFile? cropped = await img_cropper.ImageCropper().cropImage( sourcePath: tempPath, aspectRatio: const img_cropper.CropAspectRatio(ratioX: 1.0, ratioY: 1.0), uiSettings: [ img_cropper.AndroidUiSettings( toolbarTitle: "Crop image", toolbarColor: Colors.black, toolbarWidgetColor: Colors.white, ), img_cropper.IOSUiSettings(title: "Crop image"), ], ); if (cropped == null) { await File(tempPath).delete(); return null; } await File(finalPath).writeAsBytes(await cropped.readAsBytes()); await File(tempPath).delete(); return uuid; } Future loadImage(String imageUuid) async { final imageDir = await imageDirectory; if (!Uuid.isValidUUID(fromString: imageUuid)) { log.warning( "Tried to load an image with an invalid UUID : '$imageUuid'.", ); return null; } final imagePath = path.join(imageDir.path, "$imageUuid.jpg"); final file = File(imagePath); if (!await file.exists()) { log.warning("Tried to load an image that does not exist: '$imagePath'."); return null; } return Image.file(file); } Future deleteImage(String imageUuid) async { final imageDir = await imageDirectory; if (!Uuid.isValidUUID(fromString: imageUuid)) { log.warning( "Tried to delete an image with an invalid UUID : '$imageUuid'.", ); return false; } final imagePath = path.join(imageDir.path, "$imageUuid.jpg"); final file = File(imagePath); if (await file.exists()) { try { await file.delete(); log.info("Image with UUID '$imageUuid' deleted successfully."); return true; } catch (e) { log.severe("Error deleting image with UUID '$imageUuid': $e"); return false; } } else { log.warning("Tried to delete an image that does not exist: '$imagePath'."); return false; } } }