diff --git a/lib/flutter_image_picker.dart b/lib/flutter_image_picker.dart index 4f063af..3ba2563 100644 --- a/lib/flutter_image_picker.dart +++ b/lib/flutter_image_picker.dart @@ -6,4 +6,5 @@ library flutter_image_picker; export 'src/services/image_picker_service.dart'; 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 8d8f1b3..5e0c217 100644 --- a/lib/src/services/image_picker_service.dart +++ b/lib/src/services/image_picker_service.dart @@ -3,7 +3,7 @@ // SPDX-License-Identifier: BSD-3-Clause 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. @@ -11,7 +11,10 @@ import 'package:image_picker/image_picker.dart'; abstract class ImagePickerService { /// [pickImage] is the function that picks the image and returns it as a [Uint8List]. /// The function requires [source], an [ImageSource] - Future pickImage(ImageSource source); + Future pickImage( + ImageSource source, { + ImagePickerConfig? config, + }); } /// The ImagePickerServiceDefault is the default implementation of the ImagePickerService. @@ -25,10 +28,15 @@ class ImagePickerServiceDefault implements 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. @override - 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 bc85db7..932c745 100644 --- a/lib/src/ui/image_picker.dart +++ b/lib/src/ui/image_picker.dart @@ -3,18 +3,18 @@ // SPDX-License-Identifier: BSD-3-Clause import 'package:flutter/material.dart'; -import 'package:flutter_image_picker/src/services/image_picker_service.dart'; +import 'package:flutter_image_picker/flutter_image_picker.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({ this.imagePickerTheme = const ImagePickerTheme(), + this.imagePickerConfig = const ImagePickerConfig(), this.imagePickerService, this.customButton, super.key, @@ -23,6 +23,9 @@ class ImagePicker extends StatelessWidget { /// 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 Widget? customButton; @@ -32,74 +35,75 @@ class ImagePicker extends StatelessWidget { @override Widget build(BuildContext context) { return 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, + 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, + ), ), ), - ), - const SizedBox( - height: 20, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - _generateIconButtonWithText( + 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( + imagePickerTheme.selectImageText, + ), + SizedBox( + width: imagePickerTheme.spaceBetweenIcons, + ), + _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( + imagePickerTheme.makePhotoText, + ), + ], + ), + 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), + backgroundColor: + 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), - ), - ], - )); + child: Text( + imagePickerTheme.closeButtonText, + style: TextStyle( + fontFamily: imagePickerTheme.font, + fontSize: imagePickerTheme.closeButtonTextSize, + color: imagePickerTheme.closeButtonTextColor, + ), + ), + ), + ) + ], + ), + const SizedBox(height: 30), + ], + ), + ); } /// The [_generateIconButtonWithText] function returns a column that includes an [IconButton] and [Text]. @@ -125,7 +129,7 @@ class ImagePicker extends StatelessWidget { final navigator = Navigator.of(context); var image = await (imagePickerService ?? ImagePickerServiceDefault()) - .pickImage(imageSource); + .pickImage(imageSource, config: imagePickerConfig); navigator.pop(image); }, child: customIcon ?? @@ -138,13 +142,12 @@ class ImagePicker extends StatelessWidget { Text( bottomText, style: TextStyle( - fontFamily: imagePickerTheme.font, - fontSize: imagePickerTheme.iconTextSize, - color: imagePickerTheme.textColor), - ), - const SizedBox( - height: 20, + fontFamily: imagePickerTheme.font, + fontSize: imagePickerTheme.iconTextSize, + color: imagePickerTheme.textColor, + ), ), + const SizedBox(height: 20), ], ); }