feat: image rotation (suite)

release/mobdr-v0.0.1
Frédérik Benoist 2023-03-30 08:50:16 +02:00
parent d063256dce
commit 1ce0d03198
4 changed files with 80 additions and 41 deletions

View File

@ -81,8 +81,6 @@ class _CustomCameraPreviewState extends State<CustomCameraPreview> {
shape: BoxShape.circle),
child: GestureDetector(
onTap: () {
/// TODO FBE delete image on local storage
fileDelete((widget.photoFiles[index]));
setState(() {
widget.photoFiles.removeAt(index);
});
@ -103,16 +101,6 @@ class _CustomCameraPreviewState extends State<CustomCameraPreview> {
);
}
Future<void> fileDelete(File file) async {
try {
if (await file.exists()) {
await file.delete();
}
} catch (e) {
print(e);
}
}
Positioned _rejectButton() {
return Positioned(
bottom: 5,

View File

@ -1,6 +1,7 @@
// ignore_for_file: prefer_const_constructors
import 'dart:ui';
import 'dart:io';
import 'package:mobdr/config/constant.dart';
@ -16,6 +17,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:path_provider/path_provider.dart';
import 'objectbox.dart';
import 'package:wakelock/wakelock.dart';
@ -59,6 +61,8 @@ class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
initDirectories();
// Initialize all bloc provider used on this entire application here
return MultiBlocProvider(
providers: [
@ -117,4 +121,23 @@ class MyApp extends StatelessWidget {
),
);
}
void initDirectories() async {
// Get the application's document directory
final Directory documentsDir = await getApplicationDocumentsDirectory();
// Create a Directory object for the "photos" directory in the documents directory
final Directory photosDir = Directory('${documentsDir.path}/photos');
// Check if the "photos" directory exists
if (await photosDir.exists()) {
print(
'The "photos" directory already exists in the documents directory.');
} else {
// Create the "photos" directory if it does not exist
await photosDir.create();
print(
'The "photos" directory has been created in the documents directory.');
}
}
}

View File

@ -68,7 +68,7 @@ class ObjectBox {
concurrentBox.removeAll();
visiteBox.removeAll();
visiteTagBox.removeAll();
photoBox.removeAll();
//photoBox.removeAll();
//photoTypologyBox.removeAll();
// Add some demo data if the box is empty.

View File

@ -8,6 +8,8 @@ import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:image/image.dart' as img;
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'package:flutter/painting.dart' show ImageProvider;
import 'package:mobdr/config/constant.dart';
import 'package:mobdr/main.dart';
@ -16,6 +18,8 @@ import 'package:mobdr/ui/home/photo_camera.dart';
import 'package:mobdr/model/photo_model.dart';
import 'package:mobdr/db/box_photo.dart';
// TODO Il faut supprimer les possibles photos du répertoire cache !
extension FileNameExtension on File {
String getFileName() {
String fileName = path.split('/').last;
@ -138,12 +142,8 @@ class _PhotoListPageState extends State<PhotoListPage> {
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(10)),
child: Image.file(
File(photoData.image),
fit: BoxFit.cover,
height: 100,
width: 150,
),
child: Image.file(File(photoData.image),
fit: BoxFit.cover, height: 100, width: 150),
),
SizedBox(
width: 10,
@ -289,8 +289,10 @@ class _PhotoListPageState extends State<PhotoListPage> {
behavior: HitTestBehavior.translucent,
onTap: () async {
await rotateAndReplaceImage(
File(_photoData[index].image));
setState(() => _listKey = GlobalKey());
File(_photoData[index].image), 90);
setState(() {
_listKey = GlobalKey();
});
Fluttertoast.showToast(
msg: 'The image has been rotated');
},
@ -310,8 +312,14 @@ class _PhotoListPageState extends State<PhotoListPage> {
),
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
showPopupDeletePhoto(index, boxImageSize);
onTap: () async {
await rotateAndReplaceImage(
File(_photoData[index].image), -90);
setState(() {
_listKey = GlobalKey();
});
Fluttertoast.showToast(
msg: 'The image has been rotated');
},
child: Container(
padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
@ -345,8 +353,6 @@ class _PhotoListPageState extends State<PhotoListPage> {
/// if the user has validated photos
if (val == true) {
savePhotos();
} else {
resetPhotos();
}
});
},
@ -384,12 +390,20 @@ class _PhotoListPageState extends State<PhotoListPage> {
);
}
void savePhotos() {
Future<bool> evictImage(String imageURL) async {
final NetworkImage provider = NetworkImage(imageURL);
return await provider.evict();
}
void savePhotos() async {
if (photoFiles.length > 0) {
final List<Photo> _listPhotos = [];
final List<PhotoModel> _listPhotosModel = [];
for (var myPhoto in photoFiles) {
for (var myTmpPhoto in photoFiles) {
/// move jpg file to photo directory
final myPhoto = await moveFileFromTempToPhotosDir(myTmpPhoto);
/// database
_listPhotos.add(Photo(
id_visite: 0,
@ -412,15 +426,9 @@ class _PhotoListPageState extends State<PhotoListPage> {
_photoData.insertAll(0, _listPhotosModel);
/// refresh widget
setState(() => _listKey = GlobalKey());
}
}
void resetPhotos() {
/// for all photos taken
for (var photo in photoFiles) {
/// delete image on local storage
deleteFile(photo);
setState(() {
_listKey = GlobalKey();
});
}
}
@ -447,10 +455,13 @@ class _PhotoListPageState extends State<PhotoListPage> {
onPressed: () {
int removeIndex = index;
var removedItem = _photoData.removeAt(removeIndex);
// delete file on database
objectbox.delPhoto(removedItem.image_name);
// delete file on locale storages
// delete file on local storage
deleteFile(new File(removedItem.image));
// This builder is just so that the animation has something
// to work with before it disappears from view since the original
// has already been deleted.
@ -494,7 +505,22 @@ class _PhotoListPageState extends State<PhotoListPage> {
);
}
Future<void> rotateAndReplaceImage(File imageFile) async {
Future<File> moveFileFromTempToPhotosDir(File tempFile) async {
// Get the application's document directory
final Directory documentsDir = await getApplicationDocumentsDirectory();
// Set the new file path with the original file name
final String newPath =
'${documentsDir.path}/photos/${tempFile.path.split('/').last}';
// Rename the file to move it to the documents directory
await tempFile.rename(newPath);
// Create and return a new File object for the new file
return File(newPath);
}
Future<void> rotateAndReplaceImage(File imageFile, int angle) async {
// Read the image file into a Uint8List
Uint8List bytes = await imageFile.readAsBytes();
@ -502,13 +528,15 @@ class _PhotoListPageState extends State<PhotoListPage> {
img.Image? image = img.decodeImage(bytes);
// Rotate the image clockwise by 90 degrees
img.Image? rotatedImage = img.copyRotate(image!, angle: 10);
img.Image? rotatedImage = img.copyRotate(image!, angle: angle);
// Encode the rotated image back into a Uint8List
Uint8List rotatedBytes = img.encodePng(rotatedImage);
// Overwrite the original file with the rotated image
deleteFile(imageFile);
await imageFile.writeAsBytes(rotatedBytes, flush: true);
await imageFile.writeAsBytes(rotatedBytes);
// remove the flutter cache image
FileImage(imageFile).evict();
}
}