1import 'package:flutter/material.dart';
 2
 3/// Base for a generic form with return value [T].
 4abstract class FormBase<T> extends StatefulWidget {
 5  /// Create a form with generic return value.
 6  const FormBase({super.key, this.initialValue});
 7
 8  /// Initial value to prefill the form with.
 9  final T? initialValue;
10
11  @override
12  FormStateBase createState();
13}
14
15/// State of a form allowing validation and result gathering using [GlobalKey].
16///
17/// ### Sample usage
18/// ```dart
19/// class SomeWidgetState extends State<SomeWidget> {
20///   final key = GlobalKey<FormStateBase>();
21///   ...
22///   FormBase(key: key),
23///   ...
24///   TextButton(
25///     child: Text('save'),
26///     onPressed: () => if (_timeFormState.currentState?.validate() ?? false) {
27///       Navigator.pop(context, _timeFormState.currentState!.save());
28///     },
29///   )
30/// ```
31abstract class FormStateBase<T, G extends FormBase> extends State<G> {
32  /// Validates all form fields and shows errors on failing form fields.
33  ///
34  /// Returns whether the all fields validated without error.
35  bool validate();
36
37  /// Parses and returns the forms current value, if [validate] passes.
38  T? save();
39
40  /// Whether an empty input field is focused.
41  ///
42  /// Used to automatically focus the last input field on back key.
43  bool isEmptyInputFocused();
44
45  /// Set the input fields with the [value].
46  ///
47  /// If [value} is null clear the form. If value contains attributes that
48  /// correspond to different fields, only the non null attributes change field
49  /// contents.
50  void fillForm(T? value);
51}