From 44b0c92ea6d2c0d8b4697bc3f1afaf4b7c57ab29 Mon Sep 17 00:00:00 2001 From: Stein Milder Date: Mon, 7 Nov 2022 14:03:20 +0100 Subject: [PATCH] feat: ImagePickerConfig for setting image size and quality --- lib/flutter_image_picker.dart | 1 + lib/src/models/image_picker_config.dart | 20 ++ lib/src/services/image_picker_service.dart | 18 +- lib/src/ui/image_picker.dart | 215 +++++++++++---------- 4 files changed, 141 insertions(+), 113 deletions(-) create mode 100644 lib/src/models/image_picker_config.dart diff --git a/lib/flutter_image_picker.dart b/lib/flutter_image_picker.dart index f503bfd..042dada 100644 --- a/lib/flutter_image_picker.dart +++ b/lib/flutter_image_picker.dart @@ -1,4 +1,5 @@ library flutter_image_picker; export 'src/models/image_picker_theme.dart'; +export 'src/models/image_picker_config.dart'; export 'src/ui/image_picker.dart'; diff --git a/lib/src/models/image_picker_config.dart b/lib/src/models/image_picker_config.dart new file mode 100644 index 0000000..e05b307 --- /dev/null +++ b/lib/src/models/image_picker_config.dart @@ -0,0 +1,20 @@ +class ImagePickerConfig { + /// The [ImagePickerConfig] is used to configure the [ImagePicker]. + const ImagePickerConfig({ + this.maxWidth, + this.maxHeight, + this.imageQuality, + }); + + /// If specified, the image will be at most `maxWidth` wide and + /// `maxHeight` tall. Otherwise the image will be returned at it's + /// original width and height. + /// The `imageQuality` argument modifies the quality of the image, ranging from 0-100 + /// where 100 is the original/max quality. If `imageQuality` is null, the image with + /// the original quality will be returned. Compression is only supported for certain + /// image types such as JPEG and on Android PNG and WebP, too. If compression is not supported for the image that is picked, + /// a warning message will be logged. + final double? maxWidth; + final double? maxHeight; + final int? imageQuality; +} diff --git a/lib/src/services/image_picker_service.dart b/lib/src/services/image_picker_service.dart index a4c1670..f6fc870 100644 --- a/lib/src/services/image_picker_service.dart +++ b/lib/src/services/image_picker_service.dart @@ -1,5 +1,6 @@ import 'dart:typed_data'; +import 'package:flutter_image_picker/src/models/image_picker_config.dart'; import 'package:image_picker/image_picker.dart'; /// The Image Picker Service class is the functionality of the Image Picker package which uses the Image Picker package to choose an image. @@ -12,10 +13,15 @@ class ImagePickerService { /// [pickImage] is the function that picks the image and returns it as a [Uint8List]. /// The function requires [source], an [ImageSource] that's the method of how the image needs to be picked, for example gallery or camera. - Future pickImage(ImageSource source) async { - var image = - await (await (imagePicker ?? ImagePicker()).pickImage(source: source)) - ?.readAsBytes(); - return image; - } + Future pickImage( + ImageSource source, { + ImagePickerConfig? config, + }) async => + await (await (imagePicker ?? ImagePicker()).pickImage( + source: source, + maxWidth: config?.maxWidth, + maxHeight: config?.maxHeight, + imageQuality: config?.imageQuality, + )) + ?.readAsBytes(); } diff --git a/lib/src/ui/image_picker.dart b/lib/src/ui/image_picker.dart index 39030e7..1e46177 100644 --- a/lib/src/ui/image_picker.dart +++ b/lib/src/ui/image_picker.dart @@ -1,24 +1,28 @@ import 'package:flutter/material.dart'; +import 'package:flutter_image_picker/flutter_image_picker.dart'; import 'package:flutter_image_picker/src/services/image_picker_service.dart'; import 'package:image_picker/image_picker.dart'; -import '../models/image_picker_theme.dart'; - -/// The Image Picker class generates the Image Picker Widget which can be displayed in your application. If you call the class you can give it 3 optional variables: +/// The Image Picker class generates the Image Picker Widget which can be displayed in your application. If you call the class you can give it 4 optional variables: /// The first one is the [ImagePickerTheme] which can be used to change the UI of the widget. -/// The second one is your own implementation of the ImagePickerService. Which can be used in testing for example. -/// The third one is a custom Button widget. +/// The second one is the [ImagePickerConfig] which can be used to configure the behaviour of the image picker. +/// The third one is your own implementation of the ImagePickerService. Which can be used in testing for example. +/// The fourth one is a custom Button widget. class ImagePicker extends StatelessWidget { - const ImagePicker( - {Key? key, - this.imagePickerTheme = const ImagePickerTheme(), - this.imagePickerService, - this.customButton}) - : super(key: key); + const ImagePicker({ + Key? key, + this.imagePickerTheme = const ImagePickerTheme(), + this.imagePickerConfig = const ImagePickerConfig(), + this.imagePickerService, + this.customButton, + }) : super(key: key); /// ImagePickerTheme can be used to change the UI of the Image Picker Widget to change the text/icons to your liking. final ImagePickerTheme imagePickerTheme; + /// ImagePickerConfig can be used to define the size and quality for the uploaded image. + final ImagePickerConfig imagePickerConfig; + /// The Image Picker Dialog can have a custom button if you want to. final StatelessWidget? customButton; @@ -26,77 +30,76 @@ class ImagePicker extends StatelessWidget { final ImagePickerService? imagePickerService; @override - Widget build(BuildContext context) { - return SingleChildScrollView( + Widget build(BuildContext context) => SingleChildScrollView( child: Column( - children: [ - ListTile( - tileColor: imagePickerTheme.titleBackgroundColor, - title: Text( - textAlign: imagePickerTheme.titleAlignment, - imagePickerTheme.title, - style: TextStyle( - fontFamily: imagePickerTheme.font, - fontSize: imagePickerTheme.titleTextSize, - color: imagePickerTheme.titleColor, + children: [ + ListTile( + tileColor: imagePickerTheme.titleBackgroundColor, + title: Text( + textAlign: imagePickerTheme.titleAlignment, + imagePickerTheme.title, + style: TextStyle( + fontFamily: imagePickerTheme.font, + fontSize: imagePickerTheme.titleTextSize, + color: imagePickerTheme.titleColor, + ), + ), ), - ), - ), - const SizedBox( - height: 20, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - _generateIconButtonWithText( - context, - imagePickerTheme.selectImageIcon, - imagePickerTheme, - Icons.image, - ImageSource.gallery, - imagePickerTheme.selectImageText), - SizedBox( - width: imagePickerTheme.spaceBetweenIcons, + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _generateIconButtonWithText( + context, + imagePickerTheme.selectImageIcon, + imagePickerTheme, + Icons.image, + ImageSource.gallery, + imagePickerTheme.selectImageText, + ), + SizedBox( + width: imagePickerTheme.spaceBetweenIcons, + ), + _generateIconButtonWithText( + context, + imagePickerTheme.makePhotoIcon, + imagePickerTheme, + Icons.camera_alt_rounded, + ImageSource.camera, + imagePickerTheme.makePhotoText, + ), + ], ), - _generateIconButtonWithText( - context, - imagePickerTheme.makePhotoIcon, - imagePickerTheme, - Icons.camera_alt_rounded, - ImageSource.camera, - imagePickerTheme.makePhotoText), - ], - ), - const SizedBox( - height: 10, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - width: imagePickerTheme.closeButtonWidth, - height: imagePickerTheme.closeButtonHeight, - child: customButton ?? - ElevatedButton( - style: ElevatedButton.styleFrom( + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + width: imagePickerTheme.closeButtonWidth, + height: imagePickerTheme.closeButtonHeight, + child: customButton ?? + ElevatedButton( + style: ElevatedButton.styleFrom( backgroundColor: - imagePickerTheme.closeButtonBackgroundColor), - onPressed: () => Navigator.of(context).pop(), - child: Text(imagePickerTheme.closeButtonText, + imagePickerTheme.closeButtonBackgroundColor, + ), + onPressed: () => Navigator.of(context).pop(), + child: Text( + imagePickerTheme.closeButtonText, style: TextStyle( fontFamily: imagePickerTheme.font, fontSize: imagePickerTheme.closeButtonTextSize, color: imagePickerTheme.closeButtonTextColor, - ))), - ) + ), + ), + ), + ) + ], + ), + const SizedBox(height: 30), ], ), - const SizedBox( - height: (30), - ), - ], - )); - } + ); /// The [_generateIconButtonWithText] function returns a column that includes an [IconButton] and [Text]. /// The function requires the following parameters to be able to generate an icon with text: @@ -106,41 +109,39 @@ class ImagePicker extends StatelessWidget { /// [imageSource] The type of [ImageSource] to be used to pick an image when pressed on the icon. /// [bottomText] The text that's displayed underneath the icon. Column _generateIconButtonWithText( - BuildContext context, - Widget? customIcon, - ImagePickerTheme imagePickerTheme, - IconData icon, - ImageSource imageSource, - String bottomText) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - InkWell( - key: Key(bottomText), - onTap: () async { - final navigator = Navigator.of(context); - var image = await (imagePickerService ?? ImagePickerService()) - .pickImage(imageSource); - navigator.pop(image); - }, - child: customIcon ?? - Icon( - icon, - size: imagePickerTheme.iconSize, - color: imagePickerTheme.iconColor, - ), - ), - Text( - bottomText, - style: TextStyle( + BuildContext context, + Widget? customIcon, + ImagePickerTheme imagePickerTheme, + IconData icon, + ImageSource imageSource, + String bottomText) => + Column( + mainAxisSize: MainAxisSize.min, + children: [ + InkWell( + key: Key(bottomText), + onTap: () async { + final navigator = Navigator.of(context); + var image = await (imagePickerService ?? ImagePickerService()) + .pickImage(imageSource, config: imagePickerConfig); + navigator.pop(image); + }, + child: customIcon ?? + Icon( + icon, + size: imagePickerTheme.iconSize, + color: imagePickerTheme.iconColor, + ), + ), + Text( + bottomText, + style: TextStyle( fontFamily: imagePickerTheme.font, fontSize: imagePickerTheme.iconTextSize, - color: imagePickerTheme.textColor), - ), - const SizedBox( - height: 20, - ), - ], - ); - } + color: imagePickerTheme.textColor, + ), + ), + const SizedBox(height: 20), + ], + ); }