Skip to content

Commit c096855

Browse files
feat: update file picker setup
1 parent 359b173 commit c096855

File tree

1 file changed

+164
-136
lines changed

1 file changed

+164
-136
lines changed

lib/src/form_builder_file_picker.dart

Lines changed: 164 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ import 'package:flutter_form_builder/flutter_form_builder.dart';
1414
/// by the [FormBuilderFilePicker].
1515
///
1616
/// [filesSetter] can be used to update the value of [FormBuilderFilePicker].
17-
typedef FileViewerBuilder = Widget Function(
18-
List<PlatformFile>? files,
19-
FormFieldSetter<List<PlatformFile>> filesSetter,
20-
);
17+
typedef FileViewerBuilder =
18+
Widget Function(
19+
List<PlatformFile>? files,
20+
FormFieldSetter<List<PlatformFile>> filesSetter,
21+
);
2122

2223
class TypeSelector {
2324
final FileType type;
@@ -77,73 +78,89 @@ class FormBuilderFilePicker
7778
final Widget Function(List<Widget> types)? customTypeViewerBuilder;
7879

7980
/// Creates field for image(s) from user device storage
80-
FormBuilderFilePicker(
81-
{
82-
//From Super
83-
super.key,
84-
required super.name,
85-
super.validator,
86-
super.initialValue,
87-
super.decoration,
88-
super.onChanged,
89-
super.valueTransformer,
90-
super.enabled,
91-
super.onSaved,
92-
super.autovalidateMode = AutovalidateMode.disabled,
93-
super.onReset,
94-
super.focusNode,
95-
this.maxFiles,
96-
this.withData = kIsWeb,
97-
this.withReadStream = false,
98-
this.allowMultiple = false,
99-
this.previewImages = true,
100-
this.typeSelectors = const [
101-
TypeSelector(type: FileType.any, selector: Icon(Icons.add_circle))
102-
],
103-
this.allowedExtensions,
104-
this.onFileLoading,
105-
this.allowCompression = true,
106-
this.compressionQuality = 30,
107-
this.customFileViewerBuilder,
108-
this.customTypeViewerBuilder})
109-
: super(
110-
builder: (FormFieldState<List<PlatformFile>?> field) {
111-
final state = field as _FormBuilderFilePickerState;
112-
113-
return InputDecorator(
114-
decoration: state.decoration.copyWith(
115-
counterText: maxFiles != null
116-
? '${state._files.length} / $maxFiles'
117-
: null),
118-
child: Column(
119-
children: <Widget>[
120-
customTypeViewerBuilder != null
121-
? customTypeViewerBuilder(
122-
state.getTypeSelectorActions(typeSelectors, field))
123-
: Row(
124-
mainAxisAlignment: MainAxisAlignment.spaceBetween,
125-
children: state.getTypeSelectorActions(
126-
typeSelectors, field),
127-
),
128-
const SizedBox(height: 3),
129-
customFileViewerBuilder != null
130-
? customFileViewerBuilder.call(state._files,
131-
(files) => state._setFiles(files ?? [], field))
132-
: state.defaultFileViewer(state._files,
133-
(files) => state._setFiles(files ?? [], field)),
134-
],
135-
),
136-
);
137-
},
138-
);
81+
FormBuilderFilePicker({
82+
//From Super
83+
super.key,
84+
required super.name,
85+
super.validator,
86+
super.initialValue,
87+
super.decoration,
88+
super.onChanged,
89+
super.valueTransformer,
90+
super.enabled,
91+
super.onSaved,
92+
super.autovalidateMode = AutovalidateMode.disabled,
93+
super.onReset,
94+
super.focusNode,
95+
this.maxFiles,
96+
this.withData = kIsWeb,
97+
this.withReadStream = false,
98+
this.allowMultiple = false,
99+
this.previewImages = true,
100+
this.typeSelectors = const [
101+
TypeSelector(type: FileType.any, selector: Icon(Icons.add_circle)),
102+
],
103+
this.allowedExtensions,
104+
this.onFileLoading,
105+
@Deprecated(
106+
'allowCompression is deprecated and will be removed in the next major version. '
107+
'Use compressionQuality instead.',
108+
)
109+
this.allowCompression = true,
110+
this.compressionQuality = 0,
111+
this.customFileViewerBuilder,
112+
this.customTypeViewerBuilder,
113+
}) : super(
114+
builder: (FormFieldState<List<PlatformFile>?> field) {
115+
final state = field as _FormBuilderFilePickerState;
116+
117+
return InputDecorator(
118+
decoration: state.decoration.copyWith(
119+
counterText:
120+
maxFiles != null
121+
? '${state._files.length} / $maxFiles'
122+
: null,
123+
),
124+
child: Column(
125+
children: <Widget>[
126+
customTypeViewerBuilder != null
127+
? customTypeViewerBuilder(
128+
state.getTypeSelectorActions(typeSelectors, field),
129+
)
130+
: Row(
131+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
132+
children: state.getTypeSelectorActions(
133+
typeSelectors,
134+
field,
135+
),
136+
),
137+
const SizedBox(height: 3),
138+
customFileViewerBuilder != null
139+
? customFileViewerBuilder.call(
140+
state._files,
141+
(files) => state._setFiles(files ?? [], field),
142+
)
143+
: state.defaultFileViewer(
144+
state._files,
145+
(files) => state._setFiles(files ?? [], field),
146+
),
147+
],
148+
),
149+
);
150+
},
151+
);
139152

140153
@override
141154
FormBuilderFieldDecorationState<FormBuilderFilePicker, List<PlatformFile>>
142-
createState() => _FormBuilderFilePickerState();
155+
createState() => _FormBuilderFilePickerState();
143156
}
144157

145-
class _FormBuilderFilePickerState extends FormBuilderFieldDecorationState<
146-
FormBuilderFilePicker, List<PlatformFile>> {
158+
class _FormBuilderFilePickerState
159+
extends
160+
FormBuilderFieldDecorationState<
161+
FormBuilderFilePicker,
162+
List<PlatformFile>
163+
> {
147164
/// Image File Extensions.
148165
///
149166
/// Note that images may be previewed.
@@ -175,14 +192,15 @@ class _FormBuilderFilePickerState extends FormBuilderFieldDecorationState<
175192
}
176193

177194
Future<void> pickFiles(
178-
FormFieldState<List<PlatformFile>?> field, FileType fileType) async {
195+
FormFieldState<List<PlatformFile>?> field,
196+
FileType fileType,
197+
) async {
179198
FilePickerResult? resultList;
180199

181200
try {
182201
resultList = await FilePicker.platform.pickFiles(
183202
type: fileType,
184203
allowedExtensions: widget.allowedExtensions,
185-
allowCompression: widget.allowCompression,
186204
compressionQuality: widget.compressionQuality,
187205
onFileLoading: widget.onFileLoading,
188206
allowMultiple: widget.allowMultiple,
@@ -205,7 +223,9 @@ class _FormBuilderFilePickerState extends FormBuilderFieldDecorationState<
205223
}
206224

207225
void _setFiles(
208-
List<PlatformFile> files, FormFieldState<List<PlatformFile>?> field) {
226+
List<PlatformFile> files,
227+
FormFieldState<List<PlatformFile>?> field,
228+
) {
209229
setState(() => _files = files);
210230
field.didChange(_files);
211231
}
@@ -216,7 +236,9 @@ class _FormBuilderFilePickerState extends FormBuilderFieldDecorationState<
216236
}
217237

218238
Widget defaultFileViewer(
219-
List<PlatformFile> files, FormFieldSetter<List<PlatformFile>> setter) {
239+
List<PlatformFile> files,
240+
FormFieldSetter<List<PlatformFile>> setter,
241+
) {
220242
final theme = Theme.of(context);
221243

222244
return LayoutBuilder(
@@ -230,27 +252,31 @@ class _FormBuilderFilePickerState extends FormBuilderFieldDecorationState<
230252
runAlignment: WrapAlignment.start,
231253
runSpacing: 10,
232254
spacing: 10,
233-
children: List.generate(
234-
files.length,
235-
(index) {
236-
return Container(
237-
height: itemSize,
238-
width: itemSize,
239-
margin: const EdgeInsets.only(right: 2),
240-
child: Stack(
241-
alignment: Alignment.bottomCenter,
242-
children: <Widget>[
243-
Container(
244-
alignment: Alignment.center,
245-
child: (imageFileExts.contains(
246-
files[index].extension!.toLowerCase()) &&
247-
widget.previewImages)
248-
? widget.withData
249-
? Image.memory(files[index].bytes!,
250-
fit: BoxFit.cover)
251-
: Image.file(File(files[index].path!),
252-
fit: BoxFit.cover)
253-
: Container(
255+
children: List.generate(files.length, (index) {
256+
return Container(
257+
height: itemSize,
258+
width: itemSize,
259+
margin: const EdgeInsets.only(right: 2),
260+
child: Stack(
261+
alignment: Alignment.bottomCenter,
262+
children: <Widget>[
263+
Container(
264+
alignment: Alignment.center,
265+
child:
266+
(imageFileExts.contains(
267+
files[index].extension!.toLowerCase(),
268+
) &&
269+
widget.previewImages)
270+
? widget.withData
271+
? Image.memory(
272+
files[index].bytes!,
273+
fit: BoxFit.cover,
274+
)
275+
: Image.file(
276+
File(files[index].path!),
277+
fit: BoxFit.cover,
278+
)
279+
: Container(
254280
alignment: Alignment.center,
255281
color: theme.primaryColor,
256282
child: Icon(
@@ -259,63 +285,65 @@ class _FormBuilderFilePickerState extends FormBuilderFieldDecorationState<
259285
size: 56,
260286
),
261287
),
288+
),
289+
Container(
290+
padding: const EdgeInsets.symmetric(horizontal: 2),
291+
width: double.infinity,
292+
color: Colors.white.withValues(alpha: .8),
293+
child: Text(
294+
files[index].name,
295+
style: theme.textTheme.bodySmall,
296+
maxLines: 2,
297+
overflow: TextOverflow.clip,
262298
),
263-
Container(
264-
padding: const EdgeInsets.symmetric(horizontal: 2),
265-
width: double.infinity,
266-
color: Colors.white.withValues(alpha: .8),
267-
child: Text(
268-
files[index].name,
269-
style: theme.textTheme.bodySmall,
270-
maxLines: 2,
271-
overflow: TextOverflow.clip,
272-
),
273-
),
274-
if (enabled)
275-
Positioned(
276-
top: 0,
277-
right: 0,
278-
child: InkWell(
279-
onTap: () {
280-
files.removeAt(index);
281-
setter.call([...files]);
282-
},
283-
child: Container(
284-
margin: const EdgeInsets.all(3),
285-
decoration: BoxDecoration(
286-
color: Colors.grey.withValues(alpha: .7),
287-
shape: BoxShape.circle,
288-
),
289-
alignment: Alignment.center,
290-
height: 22,
291-
width: 22,
292-
child: const Icon(
293-
Icons.close,
294-
size: 18,
295-
color: Colors.white,
296-
),
299+
),
300+
if (enabled)
301+
Positioned(
302+
top: 0,
303+
right: 0,
304+
child: InkWell(
305+
onTap: () {
306+
files.removeAt(index);
307+
setter.call([...files]);
308+
},
309+
child: Container(
310+
margin: const EdgeInsets.all(3),
311+
decoration: BoxDecoration(
312+
color: Colors.grey.withValues(alpha: .7),
313+
shape: BoxShape.circle,
314+
),
315+
alignment: Alignment.center,
316+
height: 22,
317+
width: 22,
318+
child: const Icon(
319+
Icons.close,
320+
size: 18,
321+
color: Colors.white,
297322
),
298323
),
299324
),
300-
],
301-
),
302-
);
303-
},
304-
),
325+
),
326+
],
327+
),
328+
);
329+
}),
305330
);
306331
},
307332
);
308333
}
309334

310-
List<Widget> getTypeSelectorActions(List<TypeSelector> typeSelectors,
311-
FormFieldState<List<PlatformFile>?> field) {
335+
List<Widget> getTypeSelectorActions(
336+
List<TypeSelector> typeSelectors,
337+
FormFieldState<List<PlatformFile>?> field,
338+
) {
312339
return <Widget>[
313340
...typeSelectors.map(
314341
(typeSelector) => InkWell(
315-
onTap: enabled &&
316-
(null == _remainingItemCount || _remainingItemCount! > 0)
317-
? () => pickFiles(field, typeSelector.type)
318-
: null,
342+
onTap:
343+
enabled &&
344+
(null == _remainingItemCount || _remainingItemCount! > 0)
345+
? () => pickFiles(field, typeSelector.type)
346+
: null,
319347
child: typeSelector.selector,
320348
),
321349
),

0 commit comments

Comments
 (0)