130 lines
3.8 KiB
Dart
130 lines
3.8 KiB
Dart
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<Uri> 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<String?> 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<Image?> 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<bool> 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;
|
|
}
|
|
}
|
|
}
|