flutterx_forms 1.4.0 copy "flutterx_forms: ^1.4.0" to clipboard
flutterx_forms: ^1.4.0 copied to clipboard

Create, validate and manage all aspects of your forms in a new simple way. :D :D :D

example/lib/main.dart

import 'package:cross_file/cross_file.dart';
import 'package:flutter/material.dart' hide DialogRoute;
import 'package:flutterx_application/flutterx_application.dart';
import 'package:flutterx_application/flutterx_ui.dart';
import 'package:flutterx_forms/flutterx_forms.dart';

class Labels extends LabelInterface {
  const Labels() : super(locale: const Locale('it', 'IT'));
}

void main() => runApplication(
  name: 'Flutterx Forms Demo',
  initialize: (context) => FormsExample.route,
  locale: () => LocaleData(labels: {const Labels()}, onLabel: (_) {}),
  routes: {FormsExample.route},
  theme: ThemeData(primarySwatch: Colors.green).copyWith(
    outlinedButtonTheme: OutlinedButtonThemeData(
      style: OutlinedButton.styleFrom(
        iconSize: 20,
        shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))),
      ),
    ),
    inputDecorationTheme: InputDecorationTheme(
      border: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(8))),
      focusedBorder: OutlineInputBorder(
        borderRadius: const BorderRadius.all(Radius.circular(12)),
        borderSide: BorderSide(color: Colors.deepPurple.shade400, width: 3),
      ),
    ),
  ),
);

class FormsExample extends StatefulWidget {
  static final ActivityRoute<void> route = ActivityRoute(
    location: '/index',
    builder: (context, args) => const FormsExample._(),
  );

  const FormsExample._();

  @override
  State<FormsExample> createState() => _FormsExampleState();
}

class _FormsExampleState extends State<FormsExample> with FormController {
  late final XFormField<String> _name = field();
  late final XFormField<String> _surname = field();
  late final XFormField<int?> _age = field();
  late final XFormField<double?> _x = field();
  late final XFormField<XFile> _id = field();
  late final XFormField<List<SampleOption>> _sampleOptions = field();
  late final XFormField<List<String>> _tags = field();
  late final XFormField<List<DateAndTime>> _dates = field();
  bool _densify = false;

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(title: const Text('Forms example')),
    body: ResponsiveScreenContent(
      child: Card(
        child: SingleChildScrollView(
          padding: const EdgeInsets.all(m12),
          child: buildForm(
            children: [
              ElevatedButton(onPressed: () => setState(() => _densify = !_densify), child: Text('Densify: $_densify')),
              const SizedBox(height: m24),
              SizedBox.square(
                dimension: 92,
                child: CustomContentInputDecorator(
                  backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow,
                  decoration: InputDecoration(labelText: 'Picture', isDense: _densify),
                  child: SizedBox.expand(
                    child: InkWell(onTap: () {}, child: const Icon(Icons.add, size: 32)),
                  ),
                ),
              ),
              const SizedBox(height: m12),
              XTextFormField(
                field: _name,
                validator: nonEmpty(() => 'Field should not be empty'),
                textInputAction: TextInputAction.next,
                initialValue: 'Paolo',
                keyboardType: TextInputType.text,
                textCapitalization: TextCapitalization.words,
                style: const TextStyle(fontSize: 16),
                decoration: InputDecoration(isDense: _densify, labelText: 'Nome', hintText: 'Giuseppe'),
              ),
              const SizedBox(height: m12),
              XTextFormField(
                field: _surname,
                initialValue: 'Bitta',
                validator: nonEmpty(() => 'Field should not be empty'),
                textInputAction: TextInputAction.done,
                keyboardType: TextInputType.text,
                textCapitalization: TextCapitalization.words,
                style: const TextStyle(fontSize: 16),
                decoration: InputDecoration(isDense: _densify, labelText: 'Surname', hintText: 'Simone'),
              ),
              const SizedBox(height: m12),
              XIntFormField(
                field: _age,
                initialValue: 34,
                validator: validateFirst([
                  nonNull(() => 'Field should not be null'),
                  gte(18, () => 'Field must ve >=18'),
                ]),
                textInputAction: TextInputAction.next,
                decoration: InputDecoration(isDense: _densify, labelText: 'Età', hintText: '18'),
              ),
              const SizedBox(height: m12),
              XDoubleFormField(
                field: _x,
                min: -2.24,
                max: 56,
                initialValue: 56,
                validator: validateFirst([
                  nonNull(() => 'Field should not be null'),
                  gte(3, () => 'Field must ve >=3'),
                ]),
                textInputAction: TextInputAction.done,
                arrows: const NumberFieldArrows(step: .5),
                decoration: InputDecoration(isDense: _densify, labelText: 'xyz', hintText: '0.4'),
              ),
              const SizedBox(height: m12),
              XSetFormField<SampleOption>(
                field: _sampleOptions,
                items: SampleOption.values,
                decoration: const InputDecoration(labelText: 'Options'),
                initialValue: const {SampleOption.option2},
                validator: (value) => (value?.length ?? 0) < 2 ? 'Min 2 elements' : null,
                itemInitialValue: (items, _) => items.first,
                addButtonText: 'Add option',
                itemBuilder: (state, field, initialValue, index, items) => XDropdownMenuFormField<SampleOption>(
                  field: field,
                  items: items,
                  initialValue: initialValue,
                  decoration: InputDecoration(
                    labelText: 'Options ${index + 1}',
                    suffixIcon: const Icon(Icons.arrow_drop_down),
                  ),
                  validator: (item) {
                    final expected = SampleOption.values[index];
                    return item == expected ? null : 'Option $expected is only valid answer';
                  },
                  menuEntryBuilder: menuEntryByLabel((item) => item.name),
                ),
              ),
              const SizedBox(height: m12),
              XTextListFormField(
                field: _tags,
                decoration: InputDecoration(isDense: _densify, labelText: 'Tags'),
                validator: listUnique(() => 'Contains duplicate'),
              ),
              const SizedBox(height: m12),
              XListFormField<DateAndTime>(
                field: _dates,
                addButtonText: 'Add date',
                itemInitialValue: (values, index) => DateAndTime(date: DateTime.now(), time: TimeOfDay.now()),
                itemBuilder: (state, field, initialValues, index) => ProxyFormField<DateAndTime>(
                  field: field,
                  decoration: InputDecoration(labelText: 'Data ${index + 1}'),
                  initialValue: initialValues[index],
                  computeFieldData: (fields) => DateAndTime(date: fields['date'], time: fields['time']),
                  builder: (state, fields) => Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      XDateTimeFormField(
                        field: fields.field('date'),
                        initialValue: DateTime.now(),
                        selectableDayPredicate: (date) => date.day.isEven,
                        decoration: InputDecoration(isDense: _densify, labelText: 'Date'),
                        validator: validateFirst([
                          nonNull(() => 'Date required'),
                          (date) => date!.day % 5 == 0 ? null : 'Must be multiple of 5',
                        ]),
                      ),
                      const SizedBox(height: m12),
                      XTimeFormField(
                        field: fields.field('time'),
                        initialValue: TimeOfDay.now(),
                        decoration: InputDecoration(isDense: _densify, labelText: 'Hour'),
                        validator: validateFirst([nonNull(() => 'Hour required')]),
                      ),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: m12),
              // FileUploadFormField(
              //     key: _id.fieldKey,
              //     focusNode: _id.focusNode,
              //     validator: nonNull(message: 'Field id required').validator,
              //     decoration: const InputDecoration(
              //         isDense: _densify,
              //         labelText: 'Id',
              //         hintText: 'Upload',
              //         suffixIconConstraints:
              //             BoxConstraints(minHeight: 52, minWidth: kMinInteractiveDimension * 2)),
              //     autovalidateMode: AutovalidateMode.onUserInteraction),
              const SizedBox(height: 500),
            ],
          ),
        ),
      ),
    ),
    floatingActionButton: FloatingActionButton(onPressed: submitForm, child: const Icon(Icons.add)),
  );

  @override
  void onFormSubmit() {
    DialogRoute(
      location: '/result',
      builder: (context, args) => AlertDialog(
        actions: const [AlertDialogAction.positive()],
        content: Text(
          'Result: \n'
          '    name: ${_name.value}\n'
          '    surname: ${_surname.value}\n'
          '    options: ${_sampleOptions.value}\n'
          '    age: ${_age.valueOrNull}\n'
          '    id: ${_id.valueOrNull?.name}\n',
        ),
      ),
    ).open(context);
  }
}

enum SampleOption { option1, option2, option3 }

@immutable
class DateAndTime {
  final DateTime? date;
  final TimeOfDay? time;

  const DateAndTime({required this.date, required this.time});
}
2
likes
0
points
1.24k
downloads

Publisher

unverified uploader

Weekly Downloads

Create, validate and manage all aspects of your forms in a new simple way. :D :D :D

Repository (GitLab)
View/report issues

License

unknown (license)

Dependencies

collection, flutter, flutterx_utils, intl

More

Packages that depend on flutterx_forms