@@ -14,10 +14,11 @@ import 'package:flutter_form_builder/flutter_form_builder.dart';
14
14
/// by the [FormBuilderFilePicker] .
15
15
///
16
16
/// [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
+ );
21
22
22
23
class TypeSelector {
23
24
final FileType type;
@@ -77,73 +78,89 @@ class FormBuilderFilePicker
77
78
final Widget Function (List <Widget > types)? customTypeViewerBuilder;
78
79
79
80
/// 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
+ );
139
152
140
153
@override
141
154
FormBuilderFieldDecorationState <FormBuilderFilePicker , List <PlatformFile >>
142
- createState () => _FormBuilderFilePickerState ();
155
+ createState () => _FormBuilderFilePickerState ();
143
156
}
144
157
145
- class _FormBuilderFilePickerState extends FormBuilderFieldDecorationState <
146
- FormBuilderFilePicker , List <PlatformFile >> {
158
+ class _FormBuilderFilePickerState
159
+ extends
160
+ FormBuilderFieldDecorationState <
161
+ FormBuilderFilePicker ,
162
+ List <PlatformFile >
163
+ > {
147
164
/// Image File Extensions.
148
165
///
149
166
/// Note that images may be previewed.
@@ -175,14 +192,15 @@ class _FormBuilderFilePickerState extends FormBuilderFieldDecorationState<
175
192
}
176
193
177
194
Future <void > pickFiles (
178
- FormFieldState <List <PlatformFile >?> field, FileType fileType) async {
195
+ FormFieldState <List <PlatformFile >?> field,
196
+ FileType fileType,
197
+ ) async {
179
198
FilePickerResult ? resultList;
180
199
181
200
try {
182
201
resultList = await FilePicker .platform.pickFiles (
183
202
type: fileType,
184
203
allowedExtensions: widget.allowedExtensions,
185
- allowCompression: widget.allowCompression,
186
204
compressionQuality: widget.compressionQuality,
187
205
onFileLoading: widget.onFileLoading,
188
206
allowMultiple: widget.allowMultiple,
@@ -205,7 +223,9 @@ class _FormBuilderFilePickerState extends FormBuilderFieldDecorationState<
205
223
}
206
224
207
225
void _setFiles (
208
- List <PlatformFile > files, FormFieldState <List <PlatformFile >?> field) {
226
+ List <PlatformFile > files,
227
+ FormFieldState <List <PlatformFile >?> field,
228
+ ) {
209
229
setState (() => _files = files);
210
230
field.didChange (_files);
211
231
}
@@ -216,7 +236,9 @@ class _FormBuilderFilePickerState extends FormBuilderFieldDecorationState<
216
236
}
217
237
218
238
Widget defaultFileViewer (
219
- List <PlatformFile > files, FormFieldSetter <List <PlatformFile >> setter) {
239
+ List <PlatformFile > files,
240
+ FormFieldSetter <List <PlatformFile >> setter,
241
+ ) {
220
242
final theme = Theme .of (context);
221
243
222
244
return LayoutBuilder (
@@ -230,27 +252,31 @@ class _FormBuilderFilePickerState extends FormBuilderFieldDecorationState<
230
252
runAlignment: WrapAlignment .start,
231
253
runSpacing: 10 ,
232
254
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 (
254
280
alignment: Alignment .center,
255
281
color: theme.primaryColor,
256
282
child: Icon (
@@ -259,63 +285,65 @@ class _FormBuilderFilePickerState extends FormBuilderFieldDecorationState<
259
285
size: 56 ,
260
286
),
261
287
),
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,
262
298
),
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,
297
322
),
298
323
),
299
324
),
300
- ] ,
301
- ) ,
302
- );
303
- },
304
- ),
325
+ ) ,
326
+ ] ,
327
+ ),
328
+ );
329
+ } ),
305
330
);
306
331
},
307
332
);
308
333
}
309
334
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
+ ) {
312
339
return < Widget > [
313
340
...typeSelectors.map (
314
341
(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 ,
319
347
child: typeSelector.selector,
320
348
),
321
349
),
0 commit comments