• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

juancastillo0 / json_form / 11788932365

12 Nov 2024 01:21AM UTC coverage: 80.651% (+6.3%) from 74.365%
11788932365

push

github

juancastillo0
Add more README docs

1659 of 2057 relevant lines covered (80.65%)

1.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.98
/lib/src/builder/array_schema_builder.dart
1
import 'package:flutter/material.dart';
2
import 'package:json_form/json_form.dart';
3
import 'package:json_form/src/builder/general_subtitle_widget.dart';
4
import 'package:json_form/src/builder/logic/widget_builder_logic.dart';
5
import 'package:json_form/src/builder/widget_builder.dart';
6
import 'package:json_form/src/fields/shared.dart';
7
import 'package:json_form/src/models/json_form_schema_style.dart';
8
import 'package:json_form/src/models/models.dart';
9

10
class ArraySchemaBuilder extends StatefulWidget {
11
  const ArraySchemaBuilder({
1✔
12
    super.key,
13
    required this.mainSchema,
14
    required this.schemaArray,
15
  });
16
  final Schema mainSchema;
17
  final SchemaArray schemaArray;
18

19
  @override
1✔
20
  State<ArraySchemaBuilder> createState() => _ArraySchemaBuilderState();
1✔
21
}
22

23
class _ArraySchemaBuilderState extends State<ArraySchemaBuilder>
24
    implements JsonFormField<List<Object?>> {
25
  late FormFieldState<List<Object?>> field;
26
  late final JsonFormValue formValue;
27
  SchemaArray get schemaArray => widget.schemaArray;
3✔
28
  bool showItems = true;
29

30
  @override
1✔
31
  String get idKey => formValue.idKey;
2✔
32

33
  bool get isCheckboxes => schemaArray.uiSchema.widget == 'checkboxes';
5✔
34
  List<Object?>? _initialValue;
35

36
  @override
1✔
37
  void initState() {
38
    super.initState();
1✔
39
    formValue = PrivateJsonFormController.setField(context, schemaArray, this);
4✔
40
    formValue.value ??= [];
3✔
41
    _initialValue = formValue.value! as List;
3✔
42
    if (_initialValue!.isNotEmpty) {
2✔
43
      // update children
44
      value = _initialValue!;
2✔
45
    }
46
  }
47

48
  @override
1✔
49
  void dispose() {
50
    // TODO: clean up
51
    // if (schemaArray.formField == this) {
52
    //   schemaArray.formField = null;
53
    // }
54
    super.dispose();
1✔
55
  }
56

57
  @override
1✔
58
  Widget build(BuildContext context) {
59
    final widgetBuilderInherited = WidgetBuilderInherited.of(context);
1✔
60
    final uiConfig = widgetBuilderInherited.uiConfig;
1✔
61

62
    final widgetBuilder = FormField<List<Object?>>(
1✔
63
      validator: (_) {
1✔
64
        return uiConfig.localizedTexts
1✔
65
            .arrayPropertiesError(schemaArray.arrayProperties, value);
4✔
66
      },
67
      initialValue: _initialValue,
1✔
68
      builder: (field) {
1✔
69
        this.field = field;
1✔
70
        return Focus(
1✔
71
          focusNode: focusNode,
1✔
72
          autofocus: schemaArray.uiSchema.autofocus,
3✔
73
          child: Builder(
1✔
74
            builder: (context) {
1✔
75
              if (isCheckboxes) {
1✔
76
                final schema = schemaArray.itemsBaseSchema as SchemaProperty;
2✔
77
                final options =
78
                    schema.enumm ?? schema.numberProperties.options();
1✔
79
                int _index = 0;
80
                return Column(
1✔
81
                  crossAxisAlignment: CrossAxisAlignment.start,
82
                  children: [
1✔
83
                    GeneralSubtitle(
1✔
84
                      field: schemaArray,
1✔
85
                      mainSchema: widget.mainSchema,
2✔
86
                    ),
87
                    Wrap(
1✔
88
                      children: options.map((option) {
2✔
89
                        final index = _index++;
1✔
90
                        final title = schema.uiSchema.enumNames != null
2✔
91
                            ? schema.uiSchema.enumNames![index]
×
92
                            : option.toString();
1✔
93
                        return CheckboxListTile(
1✔
94
                          key: JsonFormKeys.arrayCheckboxItem(idKey, index),
2✔
95
                          title: Text(
1✔
96
                            title,
97
                            style: uiConfig.fieldInput,
1✔
98
                          ),
99
                          value: field.value != null &&
1✔
100
                              field.value!.contains(option),
2✔
101
                          onChanged: (_) {
1✔
102
                            selectCheckbox(option);
1✔
103
                          },
104
                        );
105
                      }).toList(growable: false),
1✔
106
                    ),
107
                    if (field.hasError) CustomErrorText(text: field.errorText!),
1✔
108
                  ],
109
                );
110
              }
111

112
              int _index = 0;
113
              final items = formValue.children.map((item) {
4✔
114
                final index = _index++;
1✔
115
                final idKey = JsonFormKeyPath.appendId(this.idKey, item.id);
3✔
116

117
                return Column(
1✔
118
                  key: JsonFormKeys.arrayItem(idKey),
1✔
119
                  mainAxisSize: MainAxisSize.min,
120
                  crossAxisAlignment: CrossAxisAlignment.start,
121
                  children: [
1✔
122
                    Row(
1✔
123
                      mainAxisAlignment: MainAxisAlignment.end,
124
                      children: [
1✔
125
                        if (uiConfig.labelPosition == LabelPosition.table)
2✔
126
                          Text(
1✔
127
                            '${index + 1}.',
2✔
128
                            style: uiConfig.fieldLabel,
1✔
129
                          ),
130
                        const Spacer(),
1✔
131
                        const SizedBox(height: 5),
1✔
132
                        if (schemaArray.uiSchema.copyable)
3✔
133
                          uiConfig.copyItemWidget(
1✔
134
                            idKey,
135
                            () => _copyItem(index),
2✔
136
                          ),
137
                        if (schemaArray.uiSchema.removable)
3✔
138
                          uiConfig.removeItemWidget(
1✔
139
                            idKey,
140
                            () => _removeItem(index),
2✔
141
                          ),
142
                        if (schemaArray.uiSchema.orderable)
3✔
143
                          ReorderableDragStartListener(
1✔
144
                            index: index,
145
                            child: const Icon(Icons.drag_handle),
146
                          ),
147
                      ],
148
                    ),
149
                    Padding(
1✔
150
                      padding: const EdgeInsets.only(bottom: 5.0, left: 5.0),
151
                      child: WidgetBuilderInherited(
1✔
152
                        controller: widgetBuilderInherited.controller,
1✔
153
                        jsonForm: widgetBuilderInherited.jsonForm,
1✔
154
                        uiConfig: widgetBuilderInherited.uiConfig,
1✔
155
                        context: context,
156
                        child: FormFromSchemaBuilder(
1✔
157
                          mainSchema: widget.mainSchema,
2✔
158
                          formValue: item,
159
                        ),
160
                      ),
161
                    ),
162
                  ],
163
                );
164
              });
165

166
              return Column(
1✔
167
                crossAxisAlignment: CrossAxisAlignment.start,
168
                children: [
1✔
169
                  const SizedBox(width: double.infinity),
170
                  GeneralSubtitle(
1✔
171
                    field: schemaArray,
1✔
172
                    mainSchema: widget.mainSchema,
2✔
173
                    trailing: IconButton(
1✔
174
                      key: JsonFormKeys.showOrHideItems(idKey),
2✔
175
                      tooltip: showItems
1✔
176
                          ? uiConfig.localizedTexts.hideItems()
2✔
177
                          : uiConfig.localizedTexts.showItems(),
2✔
178
                      visualDensity: VisualDensity.compact,
179
                      onPressed: () {
1✔
180
                        setState(() {
2✔
181
                          showItems = !showItems;
2✔
182
                        });
183
                      },
184
                      icon: Row(
1✔
185
                        children: [
1✔
186
                          Text(
1✔
187
                            formValue.children.length.toString(),
4✔
188
                            style: uiConfig.subtitle,
1✔
189
                          ),
190
                          if (showItems)
1✔
191
                            const Icon(Icons.arrow_drop_up_outlined)
1✔
192
                          else
193
                            const Icon(Icons.arrow_drop_down_outlined),
1✔
194
                        ],
195
                      ),
196
                    ),
197
                  ),
198
                  if (!showItems)
1✔
199
                    const SizedBox()
1✔
200
                  else if (schemaArray.uiSchema.orderable)
3✔
201
                    ReorderableListView(
1✔
202
                      shrinkWrap: true,
203
                      buildDefaultDragHandles: false,
204
                      physics: const NeverScrollableScrollPhysics(),
205
                      onReorder: (oldIndex, newIndex) {
×
206
                        setState(() {
×
207
                          final toRemove =
208
                              newIndex > oldIndex ? oldIndex : oldIndex + 1;
×
209
                          final array = formValue.children;
×
210
                          formValue.children.insert(newIndex, array[oldIndex]);
×
211
                          array.removeAt(toRemove);
×
212
                        });
213
                      },
214
                      children: items.toList(growable: false),
1✔
215
                    )
216
                  else
217
                    ...items,
×
218
                  if (field.hasError) CustomErrorText(text: field.errorText!),
3✔
219
                ],
220
              );
221
            },
222
          ),
223
        );
224
      },
225
    );
226

227
    return FormSection(
1✔
228
      child: Column(
1✔
229
        children: [
1✔
230
          widgetBuilder,
231
          if (!schemaArray.isArrayMultipleFile() &&
2✔
232
              schemaArray.uiSchema.addable &&
3✔
233
              !isCheckboxes)
1✔
234
            Align(
1✔
235
              alignment: Alignment.centerRight,
236
              child: uiConfig.addItemWidget(formValue, _addItem),
3✔
237
            ),
238
        ],
239
      ),
240
    );
241
  }
242

243
  void _addItem() {
1✔
244
    setState(() {
2✔
245
      formValue.addArrayChild(null);
2✔
246
    });
247
  }
248

249
  void _removeItem(int index) {
1✔
250
    setState(() {
2✔
251
      formValue.children.removeAt(index);
3✔
252

253
      /// cleans up the output data in the controller
254
      WidgetBuilderInherited.of(context)
2✔
255
          .controller
1✔
256
          .updateDataInPlace(idKey, (a) => a);
3✔
257
    });
258
  }
259

260
  void _copyItem(int index) {
1✔
261
    setState(() {
2✔
262
      formValue.addArrayChild(null, baseValue: formValue.children[index]);
5✔
263
    });
264
  }
265

266
  void selectCheckbox(Object? option) {
1✔
267
    setState(() {
2✔
268
      WidgetBuilderInherited.of(context).controller.updateDataInPlace(
4✔
269
        idKey,
1✔
270
        (a) {
1✔
271
          final valueList = (a as List?)?.toList() ?? [];
1✔
272
          final i = valueList.indexOf(option);
1✔
273
          if (i != -1) {
2✔
274
            valueList.removeAt(i);
1✔
275
          } else {
276
            valueList.add(option);
1✔
277
          }
278
          field.didChange(valueList);
2✔
279
          return valueList;
280
        },
281
      );
282
    });
283
  }
284

285
  @override
1✔
286
  List<Object?> get value =>
287
      isCheckboxes ? field.value! : formValue.toJson()! as List<Object?>;
5✔
288

289
  @override
290
  final focusNode = FocusNode();
291

292
  @override
1✔
293
  JsonSchemaInfo get property => schemaArray;
1✔
294

295
  @override
1✔
296
  set value(List<Object?> newValue) {
297
    if (isCheckboxes) {
1✔
298
      field.didChange(newValue);
2✔
299
      formValue.value = newValue;
2✔
300
    } else {
301
      while (formValue.children.length != newValue.length) {
5✔
302
        if (formValue.children.length < newValue.length) {
5✔
303
          formValue.addArrayChild(null);
2✔
304
        } else {
305
          formValue.children.removeLast();
×
306
        }
307
      }
308
      for (var i = 0; i < newValue.length; i++) {
2✔
309
        final item = formValue.children[i];
3✔
310
        if (item.field == null) {
1✔
311
          if (mounted) setState(() {});
3✔
312
          break;
313
        }
314
        item.field!.value = newValue[i];
×
315
      }
316
    }
317
  }
318
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc