Skip to content
This repository has been archived by the owner on Jan 17, 2024. It is now read-only.

Commit

Permalink
feat(ImagePicker): Display image cropper when an image is picked
Browse files Browse the repository at this point in the history
* feat(ImagePicker): Display image cropper when an image is picked

* feat(ImageCropper): Localize strings

* fix(ImageCropper): Remove unneeded google maps dependency
  • Loading branch information
IsAvaible authored Jan 5, 2024
1 parent 119fddd commit 683bd71
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 51 deletions.
4 changes: 4 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
Expand Down
9 changes: 9 additions & 0 deletions android/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="ucrop_label_original">Original</string>
<string name="ucrop_label_edit_photo">Foto Bearbeiten</string>
<string name="ucrop_menu_next">Nächstes</string>
<string name="ucrop_rotate">Rotieren</string>
<string name="ucrop_scale">Skalieren</string>
<string name="ucrop_crop">Zuschneiden</string>
</resources>
103 changes: 60 additions & 43 deletions lib/components/ConfirmationDialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,55 +25,72 @@ class ConfirmationDialog extends StatelessWidget {

@override
Widget build(BuildContext context) {
return AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0),
return Stack(
children: [
GestureDetector(
onTap: onCancel,
child: DecoratedBox(
decoration: BoxDecoration(color: Colors.black.withAlpha(100)),
child: Container(),
),
),
),
contentPadding: const EdgeInsets.all(16.0),
content: SizedBox(
width: 300.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 30,
horizontal: 10,
),
child: Text(
description,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 20.0, fontWeight: FontWeight.w400),
Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 30),
child: AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
TextButton(
onPressed: onConfirm,
child: Text(
confirmButtonText,
style: const TextStyle(
color: Colors.red,
fontSize: 20.0,
contentPadding: const EdgeInsets.all(16.0),
content: SizedBox(
width: 300.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 30,
horizontal: 10,
),
child: Text(
description,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 20.0, fontWeight: FontWeight.w400),
),
),
),
),
TextButton(
onPressed: onCancel,
child: Text(
cancelButtonText,
style: const TextStyle(color: Colors.black, fontSize: 20.0),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
TextButton(
onPressed: onConfirm,
child: Text(
confirmButtonText,
style: const TextStyle(
color: Colors.red,
fontSize: 20.0,
),
),
),
TextButton(
onPressed: onCancel,
child: Text(
cancelButtonText,
style: const TextStyle(
color: Colors.black, fontSize: 20.0),
),
),
],
),
],
),
],
),
),
],
),
),
),
],
);
}
}
7 changes: 4 additions & 3 deletions lib/components/ImagePicker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ class ImagePicker extends StatefulWidget {
final Function(File?) onImageSelected;

File? image;
final bool onlySquareCrop;

ImagePicker({super.key, required this.onImageSelected, this.image});
ImagePicker({super.key, required this.onImageSelected, this.image, this.onlySquareCrop = false});

@override
_ImagePickerState createState() => _ImagePickerState();
Expand All @@ -18,7 +19,7 @@ class ImagePicker extends StatefulWidget {
class _ImagePickerState extends State<ImagePicker> {
Future getImage() async {
try {
final pickedFile = await ImageManager.pickImage(context);
final pickedFile = await ImageManager.pickAndCropImage(context, onlySquareCrop: widget.onlySquareCrop);

final _i = File(pickedFile.path);
if (_i.lengthSync() > 50 * 1024 * 1024) {
Expand All @@ -36,7 +37,7 @@ class _ImagePickerState extends State<ImagePicker> {
widget.onImageSelected(widget.image);
}
} catch (e) {
if (e.toString() != "Exception: No image selected") {
if (e.toString() != "Exception: Image cropping failed" && e.toString() != "Exception: No image selected") {
context.showToast(
Toast.levelToast(
message: "Fehler beim Laden des Bildes",
Expand Down
44 changes: 41 additions & 3 deletions lib/imagemanager/ImageManager.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'dart:io';
import 'package:biersommelier/theme/theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:uuid/uuid.dart';
Expand Down Expand Up @@ -29,7 +31,7 @@ class ImageManager {
// Load a placeholder image
//return Image.asset('assets/icons/review_full.png');

// check if image in asstes/demo/key.png exists, if not load assets/icons/review_full.png
// check if image in assets/demo/key.png exists, if not load assets/icons/review_full.png
try {
final image = await rootBundle.load('assets/demo/$key.png');
return Image.memory(image.buffer.asUint8List());
Expand Down Expand Up @@ -69,7 +71,8 @@ class ImageManager {
}
}

static Future<File> pickImage(BuildContext context) async {
/// Opens the image picker and returns the cropped image
static Future<CroppedFile> pickAndCropImage(BuildContext context, {bool onlySquareCrop = false}) async {
final ImagePicker picker = ImagePicker();
// Show dialog to ask user for source type
final ImageSource? source = await showDialog<ImageSource>(
Expand Down Expand Up @@ -111,9 +114,44 @@ class ImageManager {

final XFile? image = await picker.pickImage(source: source);
if (image != null) {
return File(image.path);
final CroppedFile? croppedFile = await _cropImage(image, context, onlySquareCrop: onlySquareCrop);
if (croppedFile == null) {
throw Exception('Image cropping failed');
}
return croppedFile;
} else {
throw Exception('No image selected');
}
}

static Future<CroppedFile?> _cropImage(XFile file, BuildContext context, {bool onlySquareCrop = false}) async {
final CroppedFile? croppedFile = await ImageCropper().cropImage(
sourcePath: file.path,
aspectRatio: onlySquareCrop ? const CropAspectRatio(ratioX: 1, ratioY: 1) : null,
aspectRatioPresets: onlySquareCrop ? [CropAspectRatioPreset.square] : [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
],
uiSettings: [
AndroidUiSettings(
toolbarTitle: 'Bild zuschneiden',
toolbarColor: Theme.of(context).colorScheme.white,
toolbarWidgetColor: Theme.of(context).colorScheme.black,
activeControlsWidgetColor: Theme.of(context).colorScheme.primary,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: onlySquareCrop,
),
IOSUiSettings(
title: 'Bild zuschneiden',
doneButtonTitle: 'Fertig',
cancelButtonTitle: 'Abbrechen',
),
],
);

return croppedFile;
}
}
2 changes: 1 addition & 1 deletion lib/pages/AddBeer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ OverlayEntry createAddBeerOverlay(BuildContext context, Function closeOverlay, B
),
ImagePicker(onImageSelected: (file) {
selectedImage = file;
}, image: selectedImage)
}, image: selectedImage, onlySquareCrop: true,)
]),
const SizedBox(
width: 16,
Expand Down
24 changes: 24 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.2"
image_cropper:
dependency: "direct main"
description:
name: image_cropper
sha256: f4bad5ed2dfff5a7ce0dfbad545b46a945c702bb6182a921488ef01ba7693111
url: "https://pub.dev"
source: hosted
version: "5.0.1"
image_cropper_for_web:
dependency: transitive
description:
name: image_cropper_for_web
sha256: "865d798b5c9d826f1185b32e5d0018c4183ddb77b7b82a931e1a06aa3b74974e"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
image_cropper_platform_interface:
dependency: transitive
description:
name: image_cropper_platform_interface
sha256: ee160d686422272aa306125f3b6fb1c1894d9b87a5e20ed33fa008e7285da11e
url: "https://pub.dev"
source: hosted
version: "5.0.0"
image_picker:
dependency: "direct main"
description:
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ dependencies:
path: ^1.8.3
path_provider: ^2.1.1
uuid: ^4.2.1
google_maps_flutter: ^2.5.0
flutter_image_compress: ^2.1.0
date_field: ^3.0.5
image_picker: any
Expand All @@ -57,6 +56,7 @@ dependencies:
provider: ^6.1.1
image_picker_android: ^0.8.9+1
flutter_typeahead: ^5.0.1
image_cropper: ^5.0.1

dev_dependencies:
flutter_test:
Expand Down
5 changes: 5 additions & 0 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
<meta name="apple-mobile-web-app-title" content="biersommelier">
<link rel="apple-touch-icon" href="icons/Icon-192.png">

<!-- Croppie -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.5/croppie.css" />
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/exif-js/2.3.0/exif.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.5/croppie.min.js"></script>

<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>

Expand Down

0 comments on commit 683bd71

Please sign in to comment.