Skip to content

Commit 417565d

Browse files
committed
improvements
1 parent bd2b7c3 commit 417565d

File tree

2 files changed

+83
-32
lines changed

2 files changed

+83
-32
lines changed

lib/src/form_builder_image_picker.dart

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class FormBuilderImagePicker extends FormBuilderField<List<dynamic>> {
5656
final Widget cameraLabel;
5757
final Widget galleryLabel;
5858
final EdgeInsets bottomSheetPadding;
59+
final bool preventPop;
5960

6061
/// fit for each image
6162
final BoxFit fit;
@@ -76,6 +77,7 @@ class FormBuilderImagePicker extends FormBuilderField<List<dynamic>> {
7677
FocusNode? focusNode,
7778
WidgetBuilder? loadingWidget,
7879
this.fit = BoxFit.cover,
80+
this.preventPop = false,
7981
this.displayCustomType,
8082
this.previewWidth = 130,
8183
this.previewHeight = 130,
@@ -142,6 +144,7 @@ class FormBuilderImagePicker extends FormBuilderField<List<dynamic>> {
142144
'Consider using displayCustomType to handle the type: ${displayItem.runtimeType}',
143145
);
144146
return Stack(
147+
key: ObjectKey(item),
145148
alignment: Alignment.topRight,
146149
children: <Widget>[
147150
Container(
@@ -193,6 +196,7 @@ class FormBuilderImagePicker extends FormBuilderField<List<dynamic>> {
193196
);
194197
} else {
195198
return GestureDetector(
199+
key: UniqueKey(),
196200
child: placeholderImage != null
197201
? Image(
198202
width: previewWidth,
@@ -212,13 +216,18 @@ class FormBuilderImagePicker extends FormBuilderField<List<dynamic>> {
212216
? iconColor ?? primaryColor
213217
: disabledColor)
214218
.withAlpha(50)),
215-
onTap: () {
216-
showModalBottomSheet<void>(
219+
onTap: () async {
220+
final remainingImages = maxImages == null
221+
? null
222+
: maxImages - value.length;
223+
await showModalBottomSheet<void>(
217224
context: state.context,
218225
builder: (_) {
219226
return ImageSourceBottomSheet(
220227
maxHeight: maxHeight,
221228
maxWidth: maxWidth,
229+
preventPop: preventPop,
230+
remainingImages: remainingImages,
222231
imageQuality: imageQuality,
223232
preferredCameraDevice: preferredCameraDevice,
224233
bottomSheetPadding: bottomSheetPadding,
@@ -228,12 +237,28 @@ class FormBuilderImagePicker extends FormBuilderField<List<dynamic>> {
228237
galleryLabel: galleryLabel,
229238
onImageSelected: (image) {
230239
state.requestFocus();
231-
field.didChange(value.toList()..add(image));
240+
field.didChange([...value, ...image]);
232241
Navigator.pop(state.context);
233242
},
234243
);
235244
},
236245
);
246+
// if (remainingImages == 1) {
247+
// } else {
248+
// final imagePicker = ImagePicker();
249+
// final picked = await imagePicker.pickMultiImage(
250+
// maxHeight: maxHeight,
251+
// maxWidth: maxWidth,
252+
// imageQuality: imageQuality,
253+
// );
254+
// if (picked != null) {
255+
// state.requestFocus();
256+
// final actualPicked = remainingImages == null
257+
// ? picked
258+
// : picked.take(remainingImages);
259+
// field.didChange([...value, ...actualPicked]);
260+
// }
261+
// }
237262
},
238263
);
239264
}

lib/src/image_source_sheet.dart

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,28 @@ class ImageSourceBottomSheet extends StatefulWidget {
1414
/// image with the original quality will be returned.
1515
final int? imageQuality;
1616

17+
final int? remainingImages;
18+
1719
/// Use preferredCameraDevice to specify the camera to use when the source is
1820
/// `ImageSource.camera`. The preferredCameraDevice is ignored when source is
1921
/// `ImageSource.gallery`. It is also ignored if the chosen camera is not
2022
/// supported on the device. Defaults to `CameraDevice.rear`.
2123
final CameraDevice preferredCameraDevice;
2224

2325
/// Callback when an image is selected.
24-
final void Function(XFile) onImageSelected;
26+
final void Function(Iterable<XFile> files) onImageSelected;
2527

2628
final Widget? cameraIcon;
2729
final Widget? galleryIcon;
2830
final Widget? cameraLabel;
2931
final Widget? galleryLabel;
3032
final EdgeInsets? bottomSheetPadding;
33+
final bool preventPop;
3134

3235
ImageSourceBottomSheet({
3336
Key? key,
37+
this.remainingImages,
38+
this.preventPop = false,
3439
this.maxHeight,
3540
this.maxWidth,
3641
this.imageQuality,
@@ -54,40 +59,61 @@ class _ImageSourceBottomSheetState extends State<ImageSourceBottomSheet> {
5459
if (_isPickingImage) return;
5560
_isPickingImage = true;
5661
final imagePicker = ImagePicker();
57-
final pickedFile = await imagePicker.pickImage(
58-
source: source,
59-
maxHeight: widget.maxHeight,
60-
maxWidth: widget.maxWidth,
61-
imageQuality: widget.imageQuality,
62-
preferredCameraDevice: widget.preferredCameraDevice,
63-
);
64-
_isPickingImage = false;
65-
if (pickedFile != null) {
66-
widget.onImageSelected(pickedFile);
62+
try {
63+
if (source == ImageSource.camera || widget.remainingImages == 1) {
64+
final pickedFile = await imagePicker.pickImage(
65+
source: source,
66+
preferredCameraDevice: widget.preferredCameraDevice,
67+
maxHeight: widget.maxHeight,
68+
maxWidth: widget.maxWidth,
69+
imageQuality: widget.imageQuality,
70+
);
71+
_isPickingImage = false;
72+
if (pickedFile != null) {
73+
widget.onImageSelected([pickedFile]);
74+
}
75+
} else {
76+
final pickedFiles = await imagePicker.pickMultiImage(
77+
maxHeight: widget.maxHeight,
78+
maxWidth: widget.maxWidth,
79+
imageQuality: widget.imageQuality,
80+
);
81+
_isPickingImage = false;
82+
if (pickedFiles != null && pickedFiles.length > 0) {
83+
widget.onImageSelected(pickedFiles);
84+
}
85+
}
86+
} catch (e) {
87+
_isPickingImage = false;
88+
rethrow;
6789
}
6890
}
6991

7092
@override
7193
Widget build(BuildContext context) {
72-
return WillPopScope(
73-
onWillPop: () async => !_isPickingImage,
74-
child: Container(
75-
padding: widget.bottomSheetPadding,
76-
child: Wrap(
77-
children: <Widget>[
78-
ListTile(
79-
leading: widget.cameraIcon,
80-
title: widget.cameraLabel,
81-
onTap: () => _onPickImage(ImageSource.camera),
82-
),
83-
ListTile(
84-
leading: widget.galleryIcon,
85-
title: widget.galleryLabel,
86-
onTap: () => _onPickImage(ImageSource.gallery),
87-
),
88-
],
89-
),
94+
Widget res = Container(
95+
padding: widget.bottomSheetPadding,
96+
child: Wrap(
97+
children: <Widget>[
98+
ListTile(
99+
leading: widget.cameraIcon,
100+
title: widget.cameraLabel,
101+
onTap: () => _onPickImage(ImageSource.camera),
102+
),
103+
ListTile(
104+
leading: widget.galleryIcon,
105+
title: widget.galleryLabel,
106+
onTap: () => _onPickImage(ImageSource.gallery),
107+
),
108+
],
90109
),
91110
);
111+
if (widget.preventPop) {
112+
res = WillPopScope(
113+
onWillPop: () async => !_isPickingImage,
114+
child: res,
115+
);
116+
}
117+
return res;
92118
}
93119
}

0 commit comments

Comments
 (0)